mirror of
https://github.com/amineo/t2-stat-parser.git
synced 2026-01-19 17:34:43 +00:00
init base frontend
This commit is contained in:
parent
ade7f7e288
commit
cfa645120d
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,5 +1,9 @@
|
||||||
.env
|
.env
|
||||||
|
node_modules
|
||||||
|
|
||||||
notes.md
|
notes.md
|
||||||
|
|
||||||
app/t2-stat-parser/serverStats/stats
|
app/t2-stat-parser/serverStats/stats
|
||||||
docker-compose.deploy.yml
|
|
||||||
|
docker-compose.deploy.yml
|
||||||
|
docker-secrets/adonis.appkey.*
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Starting FTP stat file download")
|
fmt.Println("Starting FTP stat file download")
|
||||||
initFTP()
|
// initFTP()
|
||||||
fmt.Println("Stat files downloaded!")
|
fmt.Println("Stat files downloaded!")
|
||||||
|
|
||||||
fmt.Println("Starting stat parser")
|
fmt.Println("Starting stat parser")
|
||||||
|
|
|
||||||
3
app/webapp/.babelrc
Normal file
3
app/webapp/.babelrc
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"plugins": ["macros"]
|
||||||
|
}
|
||||||
9
app/webapp/.editorconfig
Normal file
9
app/webapp/.editorconfig
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
12
app/webapp/.gitignore
vendored
Normal file
12
app/webapp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Adonis directory for storing tmp files
|
||||||
|
tmp
|
||||||
|
|
||||||
|
# Don't store build
|
||||||
|
build
|
||||||
|
|
||||||
|
# Environment variables, never commit this file
|
||||||
|
.env
|
||||||
|
|
||||||
|
public/hot
|
||||||
|
public/mix-manifest.json
|
||||||
|
public/dist
|
||||||
9
app/webapp/README.md
Normal file
9
app/webapp/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Adonis Slim App
|
||||||
|
|
||||||
|
The Adonis slim app is the tinest boilerplate to create Adonisjs applications with minimal footprint and you get all the goodies of Adonis IoC container, autoloading, ace commands etc.
|
||||||
|
|
||||||
|
## What's next?
|
||||||
|
|
||||||
|
This project structure can scale as you go, simply execute the `ace` commands to create **Controllers**, **Models**, etc for you.
|
||||||
|
|
||||||
|
Also make sure to read the [guides](http://dev.adonisjs.com/docs/4.0/installation)
|
||||||
21
app/webapp/ace
Normal file
21
app/webapp/ace
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Ace Commands
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The ace file is just a regular Javascript file but with no extension. You
|
||||||
|
| can call `node ace` followed by the command name and it just works.
|
||||||
|
|
|
||||||
|
| Also you can use `adonis` followed by the command name, since the adonis
|
||||||
|
| global proxy all the ace commands.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { Ignitor } = require('@adonisjs/ignitor')
|
||||||
|
|
||||||
|
new Ignitor(require('@adonisjs/fold'))
|
||||||
|
.appRoot(__dirname)
|
||||||
|
.fireAce()
|
||||||
|
.catch(console.error)
|
||||||
6
app/webapp/app/Controllers/Http/GameController.js
Normal file
6
app/webapp/app/Controllers/Http/GameController.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
class GameController {
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = GameController
|
||||||
12
app/webapp/app/Controllers/Http/IndexController.js
Normal file
12
app/webapp/app/Controllers/Http/IndexController.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
class IndexController {
|
||||||
|
|
||||||
|
index({ inertia }) {
|
||||||
|
const pageTitle = "Home!"
|
||||||
|
return inertia.render('Index', { pageTitle }, { edgeVar: 'server-variable' })
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = IndexController
|
||||||
40
app/webapp/app/Controllers/Http/PlayerController.js
Normal file
40
app/webapp/app/Controllers/Http/PlayerController.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const Database = use('Database')
|
||||||
|
|
||||||
|
class PlayerController {
|
||||||
|
|
||||||
|
// Main Players List
|
||||||
|
async index({ inertia }) {
|
||||||
|
const pageTitle = "All Players"
|
||||||
|
const players = await Database.table('players')
|
||||||
|
.distinct('player_guid',
|
||||||
|
'player_name',
|
||||||
|
'total_games_ctfgame',
|
||||||
|
'total_games_dmgame',
|
||||||
|
'total_games_lakrabbitgame',
|
||||||
|
'total_games_sctfgame',
|
||||||
|
'updated_at')
|
||||||
|
.groupBy('player_guid')
|
||||||
|
.orderBy('player_name', 'asc')
|
||||||
|
.limit(2500)
|
||||||
|
|
||||||
|
return inertia.render('Players/Main', { pageTitle, players }, { edgeVar: 'server-variable' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player Detail
|
||||||
|
async player({ inertia, request }) {
|
||||||
|
const playerInfo = await Database.from('players').where({ player_guid: request.params.player_guid })
|
||||||
|
const playerStatData = await Database.from('games').where({ player_guid: request.params.player_guid })
|
||||||
|
|
||||||
|
let playerData = {
|
||||||
|
player: playerInfo[0],
|
||||||
|
stats: playerStatData
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageTitle = playerData.player.player_name
|
||||||
|
return inertia.render('Players/Player', { pageTitle, playerData }, { edgeVar: 'server-variable' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PlayerController
|
||||||
10
app/webapp/babel-plugin-macros.config.js
Normal file
10
app/webapp/babel-plugin-macros.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
// babel-plugin-macros.config.js
|
||||||
|
module.exports = {
|
||||||
|
twin: {
|
||||||
|
config: './tailwind.config.js',
|
||||||
|
styled: '@emotion/styled',
|
||||||
|
format: 'auto',
|
||||||
|
hasSuggestions: true,
|
||||||
|
debug: false
|
||||||
|
}
|
||||||
|
}
|
||||||
243
app/webapp/config/app.js
Normal file
243
app/webapp/config/app.js
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/** @type {import('@adonisjs/framework/src/Env')} */
|
||||||
|
const Env = use('Env')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value is the name of your application and can used when you
|
||||||
|
| need to place the application's name in a email, view or
|
||||||
|
| other location.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
name: Env.get('APP_NAME', 'AdonisJs'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| App Key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| App key is a randomly generated 16 or 32 characters long string required
|
||||||
|
| to encrypted cookies, sessions and other sensitive data.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
appKey: Env.getOrFail('APP_KEY'),
|
||||||
|
|
||||||
|
http: {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Allow Method Spoofing
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Method spoofing allows to make requests by spoofing the http verb.
|
||||||
|
| Which means you can make a GET request but instruct the server to
|
||||||
|
| treat as a POST or PUT request. If you want this feature, set the
|
||||||
|
| below value to true.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
allowMethodSpoofing: true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Trust Proxy
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Trust proxy defines whether X-Forwaded-* headers should be trusted or not.
|
||||||
|
| When your application is behind a proxy server like nginx, these values
|
||||||
|
| are set automatically and should be trusted. Apart from setting it
|
||||||
|
| to true or false Adonis supports handful or ways to allow proxy
|
||||||
|
| values. Read documentation for that.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
trustProxy: false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Subdomains
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Offset to be used for returning subdomains for a given request.For
|
||||||
|
| majority of applications it will be 2, until you have nested
|
||||||
|
| sudomains.
|
||||||
|
| cheatsheet.adonisjs.com - offset - 2
|
||||||
|
| virk.cheatsheet.adonisjs.com - offset - 3
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
subdomainOffset: 2,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JSONP Callback
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Default jsonp callback to be used when callback query string is missing
|
||||||
|
| in request url.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
jsonpCallback: 'callback',
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Etag
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Set etag on all HTTP response. In order to disable for selected routes,
|
||||||
|
| you can call the `response.send` with an options object as follows.
|
||||||
|
|
|
||||||
|
| response.send('Hello', { ignoreEtag: true })
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
etag: false
|
||||||
|
},
|
||||||
|
|
||||||
|
views: {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Views
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Define whether or not to cache the compiled view. Set it to true in
|
||||||
|
| production to optimize view loading time.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
cache: Env.get('CACHE_VIEWS', true)
|
||||||
|
},
|
||||||
|
|
||||||
|
static: {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Dot Files
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Define how to treat dot files when trying to server static resources.
|
||||||
|
| By default it is set to ignore, which will pretend that dotfiles
|
||||||
|
| does not exists.
|
||||||
|
|
|
||||||
|
| Can be one of the following
|
||||||
|
| ignore, deny, allow
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
dotfiles: 'ignore',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ETag
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Enable or disable etag generation
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
etag: true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Extensions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Set file extension fallbacks. When set, if a file is not found, the given
|
||||||
|
| extensions will be added to the file name and search for. The first
|
||||||
|
| that exists will be served. Example: ['html', 'htm'].
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
extensions: false
|
||||||
|
},
|
||||||
|
|
||||||
|
locales: {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Loader
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The loader to be used for fetching and updating locales. Below is the
|
||||||
|
| list of available options.
|
||||||
|
|
|
||||||
|
| file, database
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
loader: 'file',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Locale
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Default locale to be used by Antl provider. You can always switch drivers
|
||||||
|
| in runtime or use the official Antl middleware to detect the driver
|
||||||
|
| based on HTTP headers/query string.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
locale: 'en'
|
||||||
|
},
|
||||||
|
|
||||||
|
logger: {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Transport
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Transport to be used for logging messages. You can have multiple
|
||||||
|
| transports using same driver.
|
||||||
|
|
|
||||||
|
| Available drivers are: `file` and `console`.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
transport: 'console',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Console Transport
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Using `console` driver for logging. This driver writes to `stdout`
|
||||||
|
| and `stderr`
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
console: {
|
||||||
|
driver: 'console',
|
||||||
|
name: 'adonis-app',
|
||||||
|
level: 'info'
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| File Transport
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| File transport uses file driver and writes log messages for a given
|
||||||
|
| file inside `tmp` directory for your app.
|
||||||
|
|
|
||||||
|
| For a different directory, set an absolute path for the filename.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
file: {
|
||||||
|
driver: 'file',
|
||||||
|
name: 'adonis-app',
|
||||||
|
filename: 'adonis.log',
|
||||||
|
level: 'info'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Generic Cookie Options
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following cookie options are generic settings used by AdonisJs to create
|
||||||
|
| cookies. However, some parts of the application like `sessions` can have
|
||||||
|
| seperate settings for cookies inside `config/session.js`.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
cookie: {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: false,
|
||||||
|
path: '/',
|
||||||
|
maxAge: 7200
|
||||||
|
}
|
||||||
|
}
|
||||||
157
app/webapp/config/bodyParser.js
Normal file
157
app/webapp/config/bodyParser.js
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| JSON Parser
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Below settings are applied when the request body contains a JSON payload.
|
||||||
|
| If you want body parser to ignore JSON payloads, then simply set `types`
|
||||||
|
| to an empty array.
|
||||||
|
*/
|
||||||
|
json: {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| limit
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Defines the limit of JSON that can be sent by the client. If payload
|
||||||
|
| is over 1mb it will not be processed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
limit: '1mb',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| strict
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When `strict` is set to true, body parser will only parse Arrays and
|
||||||
|
| Object. Otherwise everything parseable by `JSON.parse` is parsed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
strict: true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| types
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Which content types are processed as JSON payloads. You are free to
|
||||||
|
| add your own types here, but the request body should be parseable
|
||||||
|
| by `JSON.parse` method.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
types: [
|
||||||
|
'application/json',
|
||||||
|
'application/json-patch+json',
|
||||||
|
'application/vnd.api+json',
|
||||||
|
'application/csp-report'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Raw Parser
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
raw: {
|
||||||
|
types: [
|
||||||
|
'text/*'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Form Parser
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
form: {
|
||||||
|
types: [
|
||||||
|
'application/x-www-form-urlencoded'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Files Parser
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
files: {
|
||||||
|
types: [
|
||||||
|
'multipart/form-data'
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Max Size
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Below value is the max size of all the files uploaded to the server. It
|
||||||
|
| is validated even before files have been processed and hard exception
|
||||||
|
| is thrown.
|
||||||
|
|
|
||||||
|
| Consider setting a reasonable value here, otherwise people may upload GB's
|
||||||
|
| of files which will keep your server busy.
|
||||||
|
|
|
||||||
|
| Also this value is considered when `autoProcess` is set to true.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
maxSize: '20mb',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Auto Process
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Whether or not to auto-process files. Since HTTP servers handle files via
|
||||||
|
| couple of specific endpoints. It is better to set this value off and
|
||||||
|
| manually process the files when required.
|
||||||
|
|
|
||||||
|
| This value can contain a boolean or an array of route patterns
|
||||||
|
| to be autoprocessed.
|
||||||
|
*/
|
||||||
|
autoProcess: true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Process Manually
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The list of routes that should not process files and instead rely on
|
||||||
|
| manual process. This list should only contain routes when autoProcess
|
||||||
|
| is to true. Otherwise everything is processed manually.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
processManually: []
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Temporary file name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Define a function, which should return a string to be used as the
|
||||||
|
| tmp file name.
|
||||||
|
|
|
||||||
|
| If not defined, Bodyparser will use `uuid` as the tmp file name.
|
||||||
|
|
|
||||||
|
| To be defined as. If you are defining the function, then do make sure
|
||||||
|
| to return a value from it.
|
||||||
|
|
|
||||||
|
| tmpFileName () {
|
||||||
|
| return 'some-unique-value'
|
||||||
|
| }
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
42
app/webapp/config/database.js
Normal file
42
app/webapp/config/database.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/** @type {import('@adonisjs/framework/src/Env')} */
|
||||||
|
const Env = use('Env')
|
||||||
|
|
||||||
|
/** @type {import('@adonisjs/ignitor/src/Helpers')} */
|
||||||
|
const Helpers = use('Helpers')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Connection
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Connection defines the default connection settings to be used while
|
||||||
|
| interacting with SQL databases.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
connection: Env.get('DB_CONNECTION', 'pg'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| PostgreSQL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here we define connection settings for PostgreSQL database.
|
||||||
|
|
|
||||||
|
| npm i --save pg
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
pg: {
|
||||||
|
client: 'pg',
|
||||||
|
connection: {
|
||||||
|
host: Env.get('DB_HOST', 'localhost'),
|
||||||
|
port: Env.get('DB_PORT', ''),
|
||||||
|
user: Env.get('DB_USER', 'root'),
|
||||||
|
password: Env.get('DB_PASSWORD', ''),
|
||||||
|
database: Env.get('DB_DATABASE', 'adonis')
|
||||||
|
},
|
||||||
|
debug: Env.get('DB_DEBUG', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
49
app/webapp/config/hash.js
Normal file
49
app/webapp/config/hash.js
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/** @type {import('@adonisjs/framework/src/Env')} */
|
||||||
|
const Env = use('Env')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Driver to be used for hashing values. The same driver is used by the
|
||||||
|
| auth module too.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
driver: Env.get('HASH_DRIVER', 'bcrypt'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Bcrypt
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Config related to bcrypt hashing. https://www.npmjs.com/package/bcrypt
|
||||||
|
| package is used internally.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
bcrypt: {
|
||||||
|
rounds: 10
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Argon
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Config related to argon. https://www.npmjs.com/package/argon2 package is
|
||||||
|
| used internally.
|
||||||
|
|
|
||||||
|
| Since argon is optional, you will have to install the dependency yourself
|
||||||
|
|
|
||||||
|
|============================================================================
|
||||||
|
| npm i argon2
|
||||||
|
|============================================================================
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
argon: {
|
||||||
|
type: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/webapp/ecosystem._DEV_.config.js
Normal file
19
app/webapp/ecosystem._DEV_.config.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
module.exports = {
|
||||||
|
apps : [{
|
||||||
|
name: process.env.APP_NAME,
|
||||||
|
script: 'server.js',
|
||||||
|
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
||||||
|
instances: 1,
|
||||||
|
autorestart: true,
|
||||||
|
watch: true,
|
||||||
|
ignore_watch:['node_modules','public','resources/js','resources/scss']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: process.env.APP_NAME + '_react',
|
||||||
|
script: 'node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js "--watch"',
|
||||||
|
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
||||||
|
instances: 1,
|
||||||
|
autorestart: false,
|
||||||
|
watch: false,
|
||||||
|
}]
|
||||||
|
};
|
||||||
19
app/webapp/ecosystem._DEV_HOT_.config.js
Normal file
19
app/webapp/ecosystem._DEV_HOT_.config.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
module.exports = {
|
||||||
|
apps : [{
|
||||||
|
name: process.env.APP_NAME,
|
||||||
|
script: 'server.js',
|
||||||
|
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
||||||
|
instances: 1,
|
||||||
|
autorestart: true,
|
||||||
|
watch: true,
|
||||||
|
ignore_watch:['node_modules','public','resources/js','resources/scss']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: process.env.APP_NAME + '_react_hot',
|
||||||
|
script: 'node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js',
|
||||||
|
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
|
||||||
|
instances: 1,
|
||||||
|
autorestart: false,
|
||||||
|
watch: false,
|
||||||
|
}]
|
||||||
|
};
|
||||||
10
app/webapp/ecosystem._PROD_.config.js
Normal file
10
app/webapp/ecosystem._PROD_.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: process.env.APP_NAME,
|
||||||
|
script: 'server.js',
|
||||||
|
autorestart: true,
|
||||||
|
instances: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
17743
app/webapp/package-lock.json
generated
Normal file
17743
app/webapp/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
78
app/webapp/package.json
Normal file
78
app/webapp/package.json
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
{
|
||||||
|
"name": "adonis-inertia-react-starter",
|
||||||
|
"version": "4.1.0",
|
||||||
|
"adonis-version": "4.1.0",
|
||||||
|
"description": "Adonis, Inertia, React, Emotion, TailwindCSS, Webpack Mix, PostCSS",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js",
|
||||||
|
"test": "node ace test",
|
||||||
|
"webpack-server": "/opt/node_modules/webpack/bin/webpack.js --progress --hide-modules --config=/opt/node_modules/laravel-mix/setup/webpack.config.js",
|
||||||
|
"watch": "npm run webpack-server -- --watch"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": "react-app"
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"adonisjs",
|
||||||
|
"adonis-app",
|
||||||
|
"inertajs",
|
||||||
|
"react"
|
||||||
|
],
|
||||||
|
"author": "",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@adonisjs/ace": "^5.0.8",
|
||||||
|
"@adonisjs/bodyparser": "^2.0.9",
|
||||||
|
"@adonisjs/cors": "^1.0.7",
|
||||||
|
"@adonisjs/fold": "^4.0.9",
|
||||||
|
"@adonisjs/framework": "^5.0.9",
|
||||||
|
"@adonisjs/ignitor": "^2.0.8",
|
||||||
|
"@adonisjs/lucid": "^6.1.3",
|
||||||
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
|
"@inertiajs/inertia": "^0.1.7",
|
||||||
|
"@inertiajs/inertia-react": "^0.1.4",
|
||||||
|
"@tailwindcss/ui": "^0.1.3",
|
||||||
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
|
"@testing-library/react": "^9.3.2",
|
||||||
|
"@testing-library/user-event": "^7.1.2",
|
||||||
|
"inertia-adonis": "^0.1.2",
|
||||||
|
"node-cookie": "^2.1.2",
|
||||||
|
"pg": "^7.18.2",
|
||||||
|
"react": "^16.13.0",
|
||||||
|
"react-dom": "^16.13.0",
|
||||||
|
"react-scripts": "3.4.0",
|
||||||
|
"tailwindcss": "^1.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/plugin-transform-react-jsx": "^7.9.1",
|
||||||
|
"@babel/preset-react": "^7.9.1",
|
||||||
|
"@emotion/core": "^10.0.28",
|
||||||
|
"@emotion/styled": "^10.0.27",
|
||||||
|
"autoprefixer": "^9.7.4",
|
||||||
|
"babel-plugin-macros": "^2.8.0",
|
||||||
|
"laravel-mix": "^5.0.4",
|
||||||
|
"laravel-mix-purgecss": "^5.0.0-rc.1",
|
||||||
|
"laravel-mix-tailwind": "^0.1.0",
|
||||||
|
"postcss-cli": "^7.1.0",
|
||||||
|
"postcss-loader": "^3.0.0",
|
||||||
|
"sass": "^1.26.3",
|
||||||
|
"twin.macro": "^1.0.0-alpha.7"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"App": "./app"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
app/webapp/public/logo.svg
Normal file
1
app/webapp/public/logo.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><svg width="36px" height="33px" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g transform="translate(0 .5)" fill="none" fill-rule="evenodd"><path d="M20 2.236L5.618 31h28.764L20 2.236z" stroke="#FFFFFF" stroke-width="2"/><path fill="#FFFFFF" d="M12 2l12 24H0"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 363 B |
BIN
app/webapp/public/pyramid.png
Normal file
BIN
app/webapp/public/pyramid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
BIN
app/webapp/public/splash.png
Normal file
BIN
app/webapp/public/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
1
app/webapp/public/title.svg
Normal file
1
app/webapp/public/title.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><svg width="186px" height="31px" viewBox="0 0 186 31" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M20.25 6.106V.1H.72v6.006h5.712v17.388H.72V29.5h19.53v-6.006h-5.712V6.106h5.712zm18.774 7.35v-5.46h-6.846V1.528h-7.182v3.108c0 2.226-1.218 3.36-3.444 3.36h-.084v5.46h3.528v8.904c0 4.578 3.528 7.686 8.82 7.686 1.932 0 3.276-.126 5.208-1.05v-5.964c-2.016.882-2.982.966-3.822.966-1.806 0-3.024-1.008-3.024-2.898v-7.644h6.846zm37.17-5.46l-3.612 13.692L68.76 7.996H63.3l-3.822 13.692-3.654-13.692h-7.308L55.068 29.5h7.266l3.696-12.516L69.684 29.5h7.308l6.552-21.504h-7.35zM95.43 7.45c6.846 0 11.424 4.746 11.424 11.256 0 6.552-4.578 11.34-11.424 11.34-6.888 0-11.466-4.788-11.466-11.34 0-6.51 4.578-11.256 11.466-11.256zm0 5.628c-2.898 0-4.62 2.352-4.62 5.628 0 3.318 1.722 5.712 4.62 5.712 2.856 0 4.578-2.394 4.578-5.712 0-3.276-1.722-5.628-4.578-5.628zm22.092.714V7.996h-7.182V29.5h7.182v-7.518c0-5.376 1.89-7.728 8.946-6.972V7.534c-4.788 0-7.686 1.806-8.946 6.258zM145.158 29.5h8.4l-7.812-11.886 7.14-9.618h-8.316l-4.284 6.552h-3.612V.1h-7.182v29.4h7.182v-8.442h3.612l4.872 8.442zm22.092-14.196h6.384c-.462-5.46-4.326-7.854-9.87-7.854-6.09 0-9.534 2.436-9.534 6.804 0 4.998 4.494 5.586 8.19 6.426 3.822.882 4.704 1.134 4.704 2.478 0 1.512-1.428 1.932-2.982 1.932-2.394 0-3.822-.966-4.074-3.486h-6.384c.336 5.88 4.536 8.442 10.542 8.442 6.132 0 9.66-2.688 9.66-7.14 0-4.998-4.41-5.628-8.736-6.594-3.234-.672-4.326-.882-4.326-2.31 0-1.134 1.176-1.848 2.856-1.848 2.268 0 3.276.882 3.57 3.15zm11.424 4.536h6.258L185.94.1h-8.316l1.05 19.74zm-.63 9.66h7.518v-6.51h-7.518v6.51z" fill="#FFFFFF" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1,15 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const FrameHeading = (props) => {
|
||||||
|
return (
|
||||||
|
<header className="bg-white shadow-sm">
|
||||||
|
<div className="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8">
|
||||||
|
<h1 className="text-lg leading-6 font-semibold text-gray-900">
|
||||||
|
{props.heading}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FrameHeading;
|
||||||
1
app/webapp/resources/js/Components/FrameHeading/index.js
Normal file
1
app/webapp/resources/js/Components/FrameHeading/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default } from './FrameHeading';
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const returnTotalGames = (player) => {
|
||||||
|
let sum = Number(player.ctf) +
|
||||||
|
Number(player.dm) +
|
||||||
|
Number(player.lak) +
|
||||||
|
Number(player.spawnctf);
|
||||||
|
return sum
|
||||||
|
};
|
||||||
|
|
||||||
|
const GameTypesPlayedBoxes = (props) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3 className="text-md leading-6 font-medium text-gray-900">
|
||||||
|
Games Played {returnTotalGames(props)}
|
||||||
|
</h3>
|
||||||
|
<div className="mt-5 grid grid-cols-1 gap-5 sm:grid-cols-4">
|
||||||
|
<div className="bg-white overflow-hidden shadow rounded-lg">
|
||||||
|
<div className="px-4 py-5 sm:p-6">
|
||||||
|
<dl>
|
||||||
|
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
||||||
|
Capture the Flag
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
||||||
|
{props.ctf}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white overflow-hidden shadow rounded-lg">
|
||||||
|
<div className="px-4 py-5 sm:p-6">
|
||||||
|
<dl>
|
||||||
|
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
||||||
|
LAK Rabbit
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
||||||
|
{props.lak}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white overflow-hidden shadow rounded-lg">
|
||||||
|
<div className="px-4 py-5 sm:p-6">
|
||||||
|
<dl>
|
||||||
|
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
||||||
|
Spawn CTF
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
||||||
|
{props.spawnctf}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white overflow-hidden shadow rounded-lg">
|
||||||
|
<div className="px-4 py-5 sm:p-6">
|
||||||
|
<dl>
|
||||||
|
<dt className="text-sm leading-5 font-medium text-gray-500 truncate">
|
||||||
|
Deathmatch
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 text-3xl leading-9 font-semibold text-gray-900">
|
||||||
|
{props.dm}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GameTypesPlayedBoxes;
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export { default } from './GameTypesPlayedBoxes';
|
||||||
56
app/webapp/resources/js/Components/TopNav/TopNav.js
Normal file
56
app/webapp/resources/js/Components/TopNav/TopNav.js
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { InertiaLink } from '@inertiajs/inertia-react'
|
||||||
|
|
||||||
|
|
||||||
|
const navItems = () =>
|
||||||
|
<div className="ml-10 flex items-baseline">
|
||||||
|
<InertiaLink href="/" className="px-3 py-2 rounded-md text-sm font-medium text-white bg-gray-900 focus:outline-none focus:text-white focus:bg-gray-700">Home</InertiaLink>
|
||||||
|
<InertiaLink href="/games" className="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Games</InertiaLink>
|
||||||
|
<InertiaLink href="/players" className="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Players</InertiaLink>
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
const TopNav = () => {
|
||||||
|
return (
|
||||||
|
<nav data-todo-x-data="{ open: false }" data-todo-at-keydown-window-escape="open = false" className="bg-gray-800">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="flex items-center justify-between h-16">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<img className="h-8 w-8" src="https://tailwindui.com/img/logos/workflow-mark-on-dark.svg" alt="Workflow logo" />
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
{ navItems() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<div className="ml-4 flex items-center md:ml-6">
|
||||||
|
<div data-todo-at-click-away="open = false" className="ml-3 relative" data-todo-x-data="{ open: false }">
|
||||||
|
<span className="inline-flex rounded-md shadow-sm">
|
||||||
|
<button type="button" className="inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
|
||||||
|
Discord
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* {Mobile nav} */}
|
||||||
|
<div className="-mr-2 flex md:hidden">
|
||||||
|
<button data-todo-at-click="open = !open" className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:bg-gray-700 focus:text-white" data-todo-x-bind-aria-label="open ? 'Close main menu' data-todo-colon- 'Main menu'" data-todo-x-bind-aria-expanded="open">
|
||||||
|
<svg className="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path data-todo-colon-className="{'hidden': open, 'inline-flex': !open }" className="inline-flex" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||||
|
<path data-todo-colon-className="{'hidden': !open, 'inline-flex': open }" className="hidden" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div data-todo-colon-className="{'block': open, 'hidden': !open}" className="hidden md:hidden">
|
||||||
|
<div className="px-2 pt-2 pb-3 sm:px-3">
|
||||||
|
{ navItems() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TopNav;
|
||||||
1
app/webapp/resources/js/Components/TopNav/index.js
Normal file
1
app/webapp/resources/js/Components/TopNav/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default } from './TopNav';
|
||||||
13
app/webapp/resources/js/Pages/Index.js
Normal file
13
app/webapp/resources/js/Pages/Index.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Layout from '@/Shared/Layout'
|
||||||
|
|
||||||
|
|
||||||
|
export default function Index(props) {
|
||||||
|
return (
|
||||||
|
<Layout title={props.pageTitle}>
|
||||||
|
<div className="border-4 border-dashed border-gray-300 rounded-lg h-96">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
59
app/webapp/resources/js/Pages/Players/Main.js
Normal file
59
app/webapp/resources/js/Pages/Players/Main.js
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { InertiaLink } from '@inertiajs/inertia-react'
|
||||||
|
import Layout from '@/Shared/Layout'
|
||||||
|
|
||||||
|
const returnTotalSumGames = (player) => {
|
||||||
|
let sum = Number(player.total_games_ctfgame) +
|
||||||
|
Number(player.total_games_dmgame) +
|
||||||
|
Number(player.total_games_lakrabbitgame) +
|
||||||
|
Number(player.total_games_sctfgame);
|
||||||
|
return sum
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const PlayerRow = (player, index) =>
|
||||||
|
<li key={index}>
|
||||||
|
<InertiaLink href={`/player/${player.player_guid}`} className="block hover:bg-gray-50 focus:outline-none focus:bg-gray-50 transition duration-150 ease-in-out">
|
||||||
|
<div className="flex items-center px-4 py-4 sm:px-6">
|
||||||
|
<div className="min-w-0 flex-1 flex items-center">
|
||||||
|
<div className="min-w-0 flex-1 md:grid md:grid-cols-2 md:gap-4">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm leading-5 font-medium text-indigo-600 truncate">{player.player_name}</div>
|
||||||
|
<div className="mt-2 flex items-center text-sm leading-5 text-gray-500">
|
||||||
|
<span className="truncate">Last Active: {player.updated_at.split(/[T]/)[0]}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm leading-5 text-gray-900">
|
||||||
|
Total Games Played
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 flex items-center">
|
||||||
|
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium leading-4 bg-gray-100 text-gray-800">{ returnTotalSumGames(player) }</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<svg className="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fillRule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clipRule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</InertiaLink>
|
||||||
|
</li>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function Players(props) {
|
||||||
|
return (
|
||||||
|
<Layout title={props.pageTitle}>
|
||||||
|
<div className="bg-white shadow overflow-hidden sm:rounded-md">
|
||||||
|
<ul>
|
||||||
|
{ props.players.map((player, index) => PlayerRow(player, index)) }
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
25
app/webapp/resources/js/Pages/Players/Player.js
Normal file
25
app/webapp/resources/js/Pages/Players/Player.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import Layout from '@/Shared/Layout'
|
||||||
|
import GameTypesPlayedBoxes from '@/Components/GameTypesPlayedBoxes'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function Player(props) {
|
||||||
|
return (
|
||||||
|
<Layout title={props.pageTitle}>
|
||||||
|
|
||||||
|
<GameTypesPlayedBoxes ctf={props.playerData.player.total_games_ctfgame}
|
||||||
|
dm={props.playerData.player.total_games_dmgame}
|
||||||
|
lak={props.playerData.player.total_games_lakrabbitgame}
|
||||||
|
spawnctf={props.playerData.player.total_games_sctfgame}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="bg-white shadow overflow-hidden sm:rounded-md">
|
||||||
|
<div>{JSON.stringify(props.playerData.player)}</div>
|
||||||
|
<div> {JSON.stringify(props.playerData.stats)}</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
25
app/webapp/resources/js/Shared/Layout.js
Normal file
25
app/webapp/resources/js/Shared/Layout.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React, { useEffect } from 'react'
|
||||||
|
|
||||||
|
import TopNav from '../Components/TopNav';
|
||||||
|
import FrameHeading from '../Components/FrameHeading'
|
||||||
|
|
||||||
|
export default function Layout({ title, children }) {
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = title;
|
||||||
|
}, [title])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TopNav />
|
||||||
|
<FrameHeading heading={title} />
|
||||||
|
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
||||||
|
<div className="px-4 py-4 sm:px-0">
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
18
app/webapp/resources/js/app.js
Normal file
18
app/webapp/resources/js/app.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { InertiaApp } from '@inertiajs/inertia-react'
|
||||||
|
import React from 'react'
|
||||||
|
import { render } from 'react-dom'
|
||||||
|
|
||||||
|
const app = document.getElementById('app')
|
||||||
|
|
||||||
|
render(
|
||||||
|
<InertiaApp
|
||||||
|
initialPage={JSON.parse(app.dataset.page)}
|
||||||
|
resolveComponent={name => import(`@/Pages/${name}`).then(module => module.default)}
|
||||||
|
/>,
|
||||||
|
app
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is required to enable HMR
|
||||||
|
if (module.hot) {
|
||||||
|
module.hot.accept();
|
||||||
|
}
|
||||||
5
app/webapp/resources/scss/main.css
Normal file
5
app/webapp/resources/scss/main.css
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import "tailwindcss/base";
|
||||||
|
|
||||||
|
@import "tailwindcss/components";
|
||||||
|
|
||||||
|
@import "tailwindcss/utilities";
|
||||||
25
app/webapp/resources/views/app.edge
Normal file
25
app/webapp/resources/views/app.edge
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>{{ edgeVar }}</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||||
|
@if(node_env().env === "production")
|
||||||
|
{{ style(versioncss('main')) }}
|
||||||
|
@else
|
||||||
|
{{ style('dist/css/main') }}
|
||||||
|
@endif
|
||||||
|
</head>
|
||||||
|
<body class="antialiased font-sans bg-gray-200">
|
||||||
|
{{{ startTag }}}
|
||||||
|
{{ edgeVar }}
|
||||||
|
@if(node_env().env === "production" || node_env().hmr === "false")
|
||||||
|
{{ script(versionjs('app')) }}
|
||||||
|
@else
|
||||||
|
{{ script('http://localhost:8081/dist/js/app.js') }}
|
||||||
|
@endif
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
app/webapp/server.js
Normal file
25
app/webapp/server.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Http server
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This file bootstrap Adonisjs to start the HTTP server. You are free to
|
||||||
|
| customize the process of booting the http server.
|
||||||
|
|
|
||||||
|
| """ Loading ace commands """
|
||||||
|
| At times you may want to load ace commands when starting the HTTP server.
|
||||||
|
| Same can be done by chaining `loadCommands()` method after
|
||||||
|
|
|
||||||
|
| """ Preloading files """
|
||||||
|
| Also you can preload files by calling `preLoad('path/to/file')` method.
|
||||||
|
| Make sure to pass relative path from the project root.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { Ignitor } = require('@adonisjs/ignitor')
|
||||||
|
|
||||||
|
new Ignitor(require('@adonisjs/fold'))
|
||||||
|
.appRoot(__dirname)
|
||||||
|
.fireHttpServer()
|
||||||
|
.catch(console.error)
|
||||||
56
app/webapp/start/app.js
Normal file
56
app/webapp/start/app.js
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Providers are building blocks for your Adonis app. Anytime you install
|
||||||
|
| a new Adonis specific package, chances are you will register the
|
||||||
|
| provider here.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
const providers = [
|
||||||
|
'@adonisjs/framework/providers/AppProvider',
|
||||||
|
'@adonisjs/framework/providers/ViewProvider',
|
||||||
|
'@adonisjs/lucid/providers/LucidProvider',
|
||||||
|
'inertia-adonis/providers/InertiaProvider'
|
||||||
|
]
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Ace Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Ace providers are required only when running ace commands. For example
|
||||||
|
| Providers for migrations, tests etc.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
const aceProviders = [
|
||||||
|
]
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Aliases
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Aliases are short unique names for IoC container bindings. You are free
|
||||||
|
| to create your own aliases.
|
||||||
|
|
|
||||||
|
| For example:
|
||||||
|
| { Route: 'Adonis/Src/Route' }
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
const aliases = {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Commands
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you store ace commands for your package
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
const commands = []
|
||||||
|
|
||||||
|
module.exports = { providers, aceProviders, aliases, commands }
|
||||||
37
app/webapp/start/hooks.js
Normal file
37
app/webapp/start/hooks.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
const { hooks } = require('@adonisjs/ignitor')
|
||||||
|
const { version } = require('../package.json')
|
||||||
|
const Helpers = use('Helpers')
|
||||||
|
|
||||||
|
const mixManifest = require(Helpers.publicPath('mix-manifest.json'))
|
||||||
|
|
||||||
|
hooks.after.providersBooted(async () => {
|
||||||
|
const View = use('View')
|
||||||
|
|
||||||
|
View.global('node_env', () => {
|
||||||
|
return { "env": process.env.NODE_ENV, "hmr": process.env.WEBPACK_HMR }
|
||||||
|
})
|
||||||
|
|
||||||
|
View.global('versionjs', (filename) => {
|
||||||
|
filename = `/dist/js/${filename}.js`
|
||||||
|
if (!mixManifest.hasOwnProperty(filename)) {
|
||||||
|
throw new Error('Could not find asset for versioning' + filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mixManifest[filename]
|
||||||
|
})
|
||||||
|
|
||||||
|
View.global('versioncss', (filename) => {
|
||||||
|
filename = `/dist/css/${filename}.css`
|
||||||
|
if (!mixManifest.hasOwnProperty(filename)) {
|
||||||
|
throw new Error('Could not find asset for versioning' + filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mixManifest[filename]
|
||||||
|
})
|
||||||
|
|
||||||
|
const Inertia = use('Adonis/Addons/Inertia')
|
||||||
|
|
||||||
|
// these vars get pushed to the inertia frontend
|
||||||
|
Inertia.setVersion(version)
|
||||||
|
Inertia.share('app.name', process.env.APP_NAME)
|
||||||
|
})
|
||||||
41
app/webapp/start/kernel.js
Normal file
41
app/webapp/start/kernel.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/** @type {import('@adonisjs/framework/src/Server')} */
|
||||||
|
const Server = use('Server')
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Global Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Global middleware are executed on each http request only when the routes
|
||||||
|
| match.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
const globalMiddleware = [
|
||||||
|
'Adonis/Middleware/Inertia'
|
||||||
|
]
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Named Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Named middleware is key/value object to conditionally add middleware on
|
||||||
|
| specific routes or group of routes.
|
||||||
|
|
|
||||||
|
| // define
|
||||||
|
| {
|
||||||
|
| auth: 'Adonis/Middleware/Auth'
|
||||||
|
| }
|
||||||
|
|
|
||||||
|
| // use
|
||||||
|
| Route.get().middleware('auth')
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
const namedMiddleware = {}
|
||||||
|
|
||||||
|
Server
|
||||||
|
.registerGlobal(globalMiddleware)
|
||||||
|
.registerNamed(namedMiddleware)
|
||||||
|
.use(['Adonis/Middleware/Static'])
|
||||||
35
app/webapp/start/routes.js
Normal file
35
app/webapp/start/routes.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Http routes are entry points to your web application. You can create
|
||||||
|
| routes for different URLs and bind Controller actions to them.
|
||||||
|
|
|
||||||
|
| A complete guide on routing is available here.
|
||||||
|
| http://adonisjs.com/docs/4.0/routing
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {typeof import('@adonisjs/framework/src/Route/Manager')} */
|
||||||
|
const Route = use('Route')
|
||||||
|
|
||||||
|
// [ Routes ]
|
||||||
|
Route.get('/', 'IndexController.index').as('home')
|
||||||
|
|
||||||
|
// [ player ]
|
||||||
|
Route.get('/players', 'PlayerController.index')
|
||||||
|
Route.get('/player/:player_guid', 'PlayerController.player')
|
||||||
|
|
||||||
|
// [ game ]
|
||||||
|
Route.get('/games', 'GameController.index')
|
||||||
|
//Route.get('/game/:game_id', 'GameController.game')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Container Healthcheck route
|
||||||
|
Route.get('/healthz', () => {
|
||||||
|
return { status: "healthy" };
|
||||||
|
})
|
||||||
15
app/webapp/tailwind.config.js
Normal file
15
app/webapp/tailwind.config.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
const defaultTheme = require('tailwindcss/defaultTheme')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variants: {},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/ui'),
|
||||||
|
]
|
||||||
|
}
|
||||||
134
app/webapp/webpack.mix.js
Normal file
134
app/webapp/webpack.mix.js
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
const mix = require('laravel-mix');
|
||||||
|
|
||||||
|
//require('laravel-mix-tailwind');
|
||||||
|
require('laravel-mix-purgecss');
|
||||||
|
const tailwindcss = require('tailwindcss');
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Mix Asset Management
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Mix provides a clean, fluent API for defining some Webpack build steps
|
||||||
|
| for your Laravel application. By default, we are compiling the Sass
|
||||||
|
| file for the application as well as bundling up all the JS files.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// transpiling, babelling, minifying and creating the public/js/main.js out of our assets
|
||||||
|
mix.setPublicPath('public')
|
||||||
|
.react('resources/js/app.js', 'public/dist/js')
|
||||||
|
// .sass('resources/scss/main.scss', 'public/dist/css')
|
||||||
|
.postCss('resources/scss/main.css', 'public/dist/css')
|
||||||
|
// .tailwind('./tailwind.config.js');
|
||||||
|
|
||||||
|
mix.webpackConfig({
|
||||||
|
output: {
|
||||||
|
chunkFilename: './dist/js/[name].[contenthash].js'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(css)/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
ident: 'postcss',
|
||||||
|
plugins: [
|
||||||
|
tailwindcss('./tailwind.config.js'),
|
||||||
|
require('autoprefixer'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@": path.resolve(
|
||||||
|
__dirname,
|
||||||
|
"resources/js"
|
||||||
|
),
|
||||||
|
"@sass": path.resolve(
|
||||||
|
__dirname,
|
||||||
|
"resources/scss"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
proxy: {
|
||||||
|
host: '0.0.0.0', // host machine ip
|
||||||
|
port: 8080,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mix.options({
|
||||||
|
hmrOptions: {
|
||||||
|
host: '0.0.0.0', // site's host name
|
||||||
|
port: 8081
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (mix.inProduction()) {
|
||||||
|
mix.purgeCss({
|
||||||
|
content: [
|
||||||
|
'./resources/**/*.edge',
|
||||||
|
'./resources/**/*.js',
|
||||||
|
'./resources/**/*.jsx',
|
||||||
|
'./resources/**/*.ts',
|
||||||
|
'./resources/**/*.tsx'
|
||||||
|
],
|
||||||
|
// default in mix
|
||||||
|
//defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
|
||||||
|
// default tailwind
|
||||||
|
defaultExtractor: content => content.match(/[\w-/.:]+(?<!:)/g) || [],
|
||||||
|
whitelistPatterns: [/-active$/, /-enter$/, /-leave-to$/]
|
||||||
|
});
|
||||||
|
|
||||||
|
mix.version();
|
||||||
|
}else{
|
||||||
|
// use SourceMaps on dev
|
||||||
|
mix.sourceMaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full mix API
|
||||||
|
// mix.js(src, output);
|
||||||
|
// mix.react(src, output); <-- Identical to mix.js(), but registers React Babel compilation.
|
||||||
|
// mix.preact(src, output); <-- Identical to mix.js(), but registers Preact compilation.
|
||||||
|
// mix.coffee(src, output); <-- Identical to mix.js(), but registers CoffeeScript compilation.
|
||||||
|
// mix.ts(src, output); <-- TypeScript support. Requires tsconfig.json to exist in the same folder as webpack.mix.js
|
||||||
|
// mix.extract(vendorLibs);
|
||||||
|
// mix.sass(src, output);
|
||||||
|
// mix.standaloneSass('src', output); <-- Faster, but isolated from Webpack.
|
||||||
|
// mix.fastSass('src', output); <-- Alias for mix.standaloneSass().
|
||||||
|
// mix.less(src, output);
|
||||||
|
// mix.stylus(src, output);
|
||||||
|
// mix.postCss(src, output, [require('postcss-some-plugin')()]);
|
||||||
|
// mix.browserSync('my-site.test');
|
||||||
|
// mix.combine(files, destination);
|
||||||
|
// mix.babel(files, destination); <-- Identical to mix.combine(), but also includes Babel compilation.
|
||||||
|
// mix.copy(from, to);
|
||||||
|
// mix.copyDirectory(fromDir, toDir);
|
||||||
|
// mix.minify(file);
|
||||||
|
// mix.sourceMaps(); // Enable sourcemaps
|
||||||
|
// mix.version(); // Enable versioning.
|
||||||
|
// mix.disableNotifications();
|
||||||
|
// mix.setPublicPath('path/to/public');
|
||||||
|
// mix.setResourceRoot('prefix/for/resource/locators');
|
||||||
|
// mix.autoload({}); <-- Will be passed to Webpack's ProvidePlugin.
|
||||||
|
// mix.webpackConfig({}); <-- Override webpack.config.js, without editing the file directly.
|
||||||
|
// mix.babelConfig({}); <-- Merge extra Babel configuration (plugins, etc.) with Mix's default.
|
||||||
|
// mix.then(function () {}) <-- Will be triggered each time Webpack finishes building.
|
||||||
|
// mix.extend(name, handler) <-- Extend Mix's API with your own components.
|
||||||
|
// mix.options({
|
||||||
|
// extractVueStyles: false, // Extract .vue component styling to file, rather than inline.
|
||||||
|
// globalVueStyles: file, // Variables file to be imported in every component.
|
||||||
|
// processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched.
|
||||||
|
// purifyCss: false, // Remove unused CSS selectors.
|
||||||
|
// uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
|
||||||
|
// postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md
|
||||||
|
// });
|
||||||
|
|
@ -29,8 +29,8 @@ RUN apk update && apk add --no-cache wget tzdata
|
||||||
#Set TimeZone
|
#Set TimeZone
|
||||||
ENV TZ=America/New_York
|
ENV TZ=America/New_York
|
||||||
|
|
||||||
#Set cron schedule (every day at 9:30am est)
|
#Set cron schedule (every day at 11:30am est)
|
||||||
RUN echo '30 9 * * * /app/start.sh' > /etc/crontabs/root
|
RUN echo '30 11 * * * /app/start.sh' > /etc/crontabs/root
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|
|
||||||
3
build/webapp/.dockerignore
Normal file
3
build/webapp/.dockerignore
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.git
|
||||||
|
node_modules
|
||||||
|
public/dist
|
||||||
67
build/webapp/Dockerfile
Normal file
67
build/webapp/Dockerfile
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# [ Stage 1 ] - install node modules
|
||||||
|
FROM node:12.2-alpine as builder
|
||||||
|
RUN apk update
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY ./app/webapp/package.json /build/package.json
|
||||||
|
COPY ./app/webapp/package-lock.json /build/package-lock.json
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
RUN npm i --global @adonisjs/cli
|
||||||
|
|
||||||
|
RUN npx adonis key:generate --echo
|
||||||
|
|
||||||
|
# ============================
|
||||||
|
# ============================
|
||||||
|
|
||||||
|
# [ Stage 2 ]
|
||||||
|
FROM node:12.2-alpine
|
||||||
|
LABEL maintainer="Anthony Mineo <anthonymineo@gmail.com>"
|
||||||
|
|
||||||
|
RUN apk update && apk add --no-cache bash curl
|
||||||
|
|
||||||
|
# Default envs as prod
|
||||||
|
ENV ENV_SILENT=true \
|
||||||
|
HOST=0.0.0.0 \
|
||||||
|
PORT=8080 \
|
||||||
|
HASH_DRIVER=bcrypt \
|
||||||
|
NODE_ENV=production \
|
||||||
|
WEBPACK_HMR=false \
|
||||||
|
CACHE_VIEWS=true \
|
||||||
|
APP_NAME=AdonisJs
|
||||||
|
ENV APP_URL=http://${HOST}:${PORT}
|
||||||
|
|
||||||
|
#ENV APP_KEY=you-need-to-generate-this
|
||||||
|
# secrets path _FILE prefix or ENV K=V
|
||||||
|
|
||||||
|
|
||||||
|
# Setup pm2 as our node process manager
|
||||||
|
# https://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/
|
||||||
|
RUN npm install pm2 -g
|
||||||
|
|
||||||
|
# Set node modules outside our app to keep it clean
|
||||||
|
COPY --from=builder /build/node_modules/ /opt/node_modules/
|
||||||
|
ENV PATH /opt/node_modules/.bin:$PATH
|
||||||
|
|
||||||
|
|
||||||
|
# Start script and config
|
||||||
|
COPY ./build/webapp/entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
# Our App
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./app/webapp /app
|
||||||
|
|
||||||
|
RUN ln -nsf /opt/node_modules /app
|
||||||
|
|
||||||
|
|
||||||
|
# Bake prod assets into image
|
||||||
|
RUN rm -rf /app/public/dist && npm run webpack-server
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=20s --timeout=30s --start-period=5s --retries=5 \
|
||||||
|
CMD curl -f http://localhost:8080/healthz || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||||
57
build/webapp/entrypoint.sh
Executable file
57
build/webapp/entrypoint.sh
Executable file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Node ENV: $NODE_ENV"
|
||||||
|
|
||||||
|
file_env() {
|
||||||
|
local var="$1"
|
||||||
|
local fileVar="${var}_FILE"
|
||||||
|
local def="${2:-}"
|
||||||
|
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
||||||
|
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
local val="$def"
|
||||||
|
if [ "${!var:-}" ]; then
|
||||||
|
val="${!var}"
|
||||||
|
elif [ "${!fileVar:-}" ]; then
|
||||||
|
val="$(< "${!fileVar}")"
|
||||||
|
fi
|
||||||
|
export "$var"="$val"
|
||||||
|
unset "$fileVar"
|
||||||
|
}
|
||||||
|
|
||||||
|
file_env 'APP_KEY'
|
||||||
|
|
||||||
|
|
||||||
|
# Exit if APP_KEY is missing, this key is important!
|
||||||
|
if [ -z "$APP_KEY" ]
|
||||||
|
then
|
||||||
|
echo >&2 "[ERROR] No ENV for APP_KEY or APP_KEY_FILE found!"
|
||||||
|
echo >&2 "Run the ./generate-adonis-app-key.sh script or provide one at runtime"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [[ "$NODE_ENV" == "development" ]]; then
|
||||||
|
echo "Prepping container for dev environment"
|
||||||
|
echo "Setting a symlink for ./node_modules -> /opt/node_modules"
|
||||||
|
ln -nsf /opt/node_modules /app
|
||||||
|
|
||||||
|
echo "Cleaning dist assets..."
|
||||||
|
rm -rf /app/public/dist
|
||||||
|
npm run webpack-server
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate a dist assets if they don't exist -- (If they were deleted on the volume mount)
|
||||||
|
[ ! -d "/app/public/dist" ] && npm run webpack-server
|
||||||
|
|
||||||
|
|
||||||
|
if [[ "$NODE_ENV" == "production" ]]; then
|
||||||
|
pm2-runtime start /app/ecosystem._PROD_.config.js
|
||||||
|
elif [[ "$WEBPACK_HMR" == "true" ]]; then
|
||||||
|
pm2-runtime start /app/ecosystem._DEV_HOT_.config.js
|
||||||
|
else
|
||||||
|
pm2-runtime start /app/ecosystem._DEV_.config.js
|
||||||
|
fi
|
||||||
|
|
@ -19,12 +19,31 @@ services:
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: "postgres://dev:dev@db:5432/t2_stats"
|
DATABASE_URL: "postgres://dev:dev@db:5432/t2_stats"
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8000:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ./app/t2-stat-parser:/app
|
- ./app/t2-stat-parser:/app
|
||||||
|
|
||||||
|
web:
|
||||||
|
environment:
|
||||||
|
DB_USER: "dev"
|
||||||
|
DB_PASSWORD: "dev"
|
||||||
|
|
||||||
|
CACHE_VIEWS: "false"
|
||||||
|
NODE_ENV: "development" # auto-reloads app on save, dev builds
|
||||||
|
WEBPACK_HMR: "true" # default is false -- this is useful for when you're focused on Frontend Dev
|
||||||
|
ports:
|
||||||
|
- "8080:8080" # adonis http port
|
||||||
|
- "8081:8081" # webpack-dev-server port
|
||||||
|
volumes:
|
||||||
|
- ./app/webapp:/app
|
||||||
|
|
||||||
# api:
|
# api:
|
||||||
# volumes:
|
# volumes:
|
||||||
# - ./app/api:/home/node/app
|
# - ./app/api:/home/node/app
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
adonis.appkey:
|
||||||
|
external: false
|
||||||
|
file: ./docker-secrets/adonis.appkey.v1
|
||||||
|
|
@ -39,7 +39,6 @@ services:
|
||||||
- db
|
- db
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
- external
|
|
||||||
deploy:
|
deploy:
|
||||||
labels:
|
labels:
|
||||||
- traefik.enable=false
|
- traefik.enable=false
|
||||||
|
|
@ -47,6 +46,38 @@ services:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
|
||||||
|
|
||||||
|
web:
|
||||||
|
image: "amineo/t2-stats-web:v0.1.3"
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./build/webapp/Dockerfile
|
||||||
|
environment:
|
||||||
|
NODE_ENV: "production" # set as default in image
|
||||||
|
CACHE_VIEWS: "true" # set as default in image
|
||||||
|
APP_NAME: "Web" # set as default in image
|
||||||
|
|
||||||
|
# APP_KEY: "You-need-to-generate-this (npx adonis key:generate --echo)"
|
||||||
|
APP_KEY_FILE: /run/secrets/adonis.appkey
|
||||||
|
|
||||||
|
DB_HOST: "db"
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USER: ""
|
||||||
|
DB_PASSWORD: ""
|
||||||
|
DB_DATABASE: t2_stats
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
- adonis.appkey
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- external
|
||||||
|
deploy:
|
||||||
|
# labels:
|
||||||
|
# - traefik.enable=false
|
||||||
|
mode: replicated
|
||||||
|
replicas: 1
|
||||||
|
|
||||||
# api:
|
# api:
|
||||||
# image: "node:12-alpine"
|
# image: "node:12-alpine"
|
||||||
# depends_on:
|
# depends_on:
|
||||||
|
|
@ -68,4 +99,10 @@ volumes:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
external:
|
external:
|
||||||
internal:
|
internal:
|
||||||
|
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
adonis.appkey:
|
||||||
|
external: true
|
||||||
|
name: adonis.appkey.v1
|
||||||
0
docker-secrets/empty.txt
Normal file
0
docker-secrets/empty.txt
Normal file
28
generate-adonis-app-key.sh
Executable file
28
generate-adonis-app-key.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Checking to see if @adonisjs/cli has been installed..."
|
||||||
|
|
||||||
|
package='@adonisjs/cli'
|
||||||
|
if [ `npm list -g | grep -c $package` -eq 0 ]; then
|
||||||
|
while true; do
|
||||||
|
echo "-----------------------------------------------"
|
||||||
|
echo " Adonis CLI not installed"
|
||||||
|
echo "-----------------------------------------------"
|
||||||
|
read -p "Would you like to install this now? [Y/N] " yn
|
||||||
|
case $yn in
|
||||||
|
[Yy]* ) npm i --global @adonisjs/cli; break;;
|
||||||
|
[Nn]* ) break;;
|
||||||
|
* ) echo "Please answer yes or no.";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "Looks good!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "Generating key..."
|
||||||
|
APPKEY=$(npx adonis key:generate --echo)
|
||||||
|
|
||||||
|
echo -n "${APPKEY/APP_KEY=}" > ./docker-secrets/adonis.appkey.v1
|
||||||
|
|
||||||
|
echo "Done! Don't share it with anyone!"
|
||||||
|
echo "The key is located here: ./docker-secrets/adonis.appkey.v1"
|
||||||
Loading…
Reference in a new issue