mirror of
https://github.com/amineo/t2-stat-parser.git
synced 2026-01-20 01:34:47 +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
|
||||
node_modules
|
||||
|
||||
notes.md
|
||||
|
||||
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() {
|
||||
fmt.Println("Starting FTP stat file download")
|
||||
initFTP()
|
||||
// initFTP()
|
||||
fmt.Println("Stat files downloaded!")
|
||||
|
||||
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
|
||||
ENV TZ=America/New_York
|
||||
|
||||
#Set cron schedule (every day at 9:30am est)
|
||||
RUN echo '30 9 * * * /app/start.sh' > /etc/crontabs/root
|
||||
#Set cron schedule (every day at 11:30am est)
|
||||
RUN echo '30 11 * * * /app/start.sh' > /etc/crontabs/root
|
||||
|
||||
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:
|
||||
DATABASE_URL: "postgres://dev:dev@db:5432/t2_stats"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8000:8080"
|
||||
volumes:
|
||||
- ./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:
|
||||
# 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
|
||||
networks:
|
||||
- internal
|
||||
- external
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.enable=false
|
||||
|
|
@ -47,6 +46,38 @@ services:
|
|||
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:
|
||||
# image: "node:12-alpine"
|
||||
# depends_on:
|
||||
|
|
@ -68,4 +99,10 @@ volumes:
|
|||
|
||||
networks:
|
||||
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