Initial commit of framework

This commit is contained in:
2020-11-01 12:50:03 -06:00
commit ad0abe5b84
47 changed files with 5416 additions and 0 deletions

0
app/assets/.gitkeep Normal file
View File

BIN
app/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/assets/flitter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,28 @@
const { Controller } = require('libflitter')
/*
* Home Controller
* -------------------------------------------------------------
* Controller for the main homepage of this Flitter app. Methods here
* are used as handlers for routes specified in the route files.
*/
class Home extends Controller {
/*
* Serve the main welcome page.
*/
welcome(req, res){
/*
* Return the welcome view.
* The page() method is added by Flitter and passes some
* helpful contextual data to the view as well.
*/
return res.page('welcome', {
user: req.user,
T: req.T,
})
}
}
module.exports = Home

View File

@@ -0,0 +1,30 @@
const { Model } = require('flitter-orm')
/*
* Example Model
* -------------------------------------------------------------
* This is a sample model. The schema or structure of the model should
* be specified here. It is then passed to flitter-orm and can be accessed
* globally using the canonical models service.
*/
class Example extends Model {
static get services() {
return [...super.services, 'output']
}
/*
* Define the flitter-orm schema of the model.
*/
static get schema() {
return {
name: String,
create_date: {type: Date, default: () => new Date},
}
}
log_name() {
this.output.info(`[Example Model] ${this.name}`)
}
}
module.exports = exports = Example

18
app/routing/Middleware.js Normal file
View File

@@ -0,0 +1,18 @@
/*
* Global Middleware Definitions
* -------------------------------------------------------------
* These middleware are applied, in order, before every request that
* Flitter handles, regardless of request type. Each middleware class
* can be referenced using the middleware's Flitter canonical name.
*
* Route-specific middleware should be specified in the corresponding
* routes file.
*/
const Middleware = [
// Injects the RequestLocalizationHelper
"i18n:Localize",
]
module.exports = exports = Middleware

View File

@@ -0,0 +1,32 @@
const { Middleware } = require('libflitter')
/*
* HomeLogger Middleware
* -------------------------------------------------------------
* This is a sample middleware. It simply prints a console message when
* the route that it is tied to is accessed. By default, it is called if
* the '/' route is accessed. It can be injected in routes globally using
* the middlewares service.
*/
class HomeLogger extends Middleware {
static get services() {
return [...super.services, 'output']
}
/*
* Run the middleware test.
* This method is required by all Flitter middleware.
* It should either call the next function in the stack,
* or it should handle the response accordingly.
*/
test(req, res, next, args) {
this.output.debug('Home was accessed!')
/*
* Call the next function in the stack.
*/
next()
}
}
module.exports = HomeLogger

View File

@@ -0,0 +1,7 @@
const Middleware = require('flitter-i18n/src/middleware/Localize')
class LocalizeMiddleware extends Middleware {
}
module.exports = exports = LocalizeMiddleware

View File

@@ -0,0 +1,7 @@
const Middleware = require('flitter-i18n/src/middleware/Scope')
class ScopeMiddleware extends Middleware {
}
module.exports = exports = ScopeMiddleware

View File

@@ -0,0 +1,43 @@
const { Middleware } = require('libflitter')
/*
* Config Middleware
* -------------------------------------------------------------
* Checks the specified configuration key (and optionally the value).
* If the configuration matches the required value, the request can
* proceed. Otherwise, a 404 will be returned.
*
* To use, add the call to your route's middleware:
*
* ['middleware::util:Config', {key: 'server.ssl.test', value: true}],
*
* In this case, the request would be allowed to proceed in the case:
* services.configs.get('server.ssl.test') === true
*
* The 'value' attribute is optional. If none is provided, the request
* can proceed if the config value is truthy.
*/
class Config extends Middleware {
static get services() {
return [...super.services, 'configs', 'output']
}
/*
* Run the middleware test.
*/
test(req, res, next, args = {}){
if ( !args.key ) return res.error(500)
const config = this.configs.get(args.key)
if ( !args.value && !config ) {
if ( !config && typeof config === 'undefined' )
this.output.warn(`util:Config middleware check failed because it tried to access a config that doesn't exist. (${key})`)
return res.error(404)
}
else if ( args.value && args.value !== config ) return res.error(404)
else return next()
}
}
module.exports = Config

View File

@@ -0,0 +1,71 @@
/*
* Index Routes
* -------------------------------------------------------------
* This is a sample routes file. Routes and their handlers should be
* defined here, but no logic should occur.
*/
const index = {
/*
* Define the prefix applied to each of these routes.
* For example, if prefix is '/auth':
* '/' becomes '/auth'
* '/login' becomes '/auth/login'
*/
prefix: '/',
/*
* Define middleware that should be applied to all
* routes defined in this file. Middleware should be
* included using its non-prefixed canonical name.
*
* You can pass arguments along to a middleware by
* specifying it as an array where the first element
* is the canonical name of the middleware and the
* second element is the argument passed to the
* handler's test() method.
*/
middleware: [
// Sets the locale scope
['i18n:Scope', {scope: 'common'}],
['HomeLogger', {note: 'arguments can be specified as the second element in this array'}],
// 'MiddlewareName', // Or without arguments
],
/*
* Define GET routes.
* These routes are registered as GET methods.
* Handlers for these routes should be specified as
* an array of canonical references to controller methods
* or middleware that are applied in order.
*/
get: {
// handlers should be a list of either controller:: or middleware:: references
// e.g. middleware::HomeLogger
// e.g. controller::Home.welcome
'/': [
'controller::Home.welcome'
],
// Placeholder for auth dashboard. You'd replace this with
// your own route protected by 'middleware::auth:UserOnly'
'/dash': [ 'controller::Home.welcome' ],
},
/*
* Define POST routes.
* These routes are registered as POST methods.
* Handlers for these routes should be specified as
* an array of canonical references to controller methods
* or middleware that are applied in order.
*/
post: {
},
// You can include other HTTP verbs here.
// Supported ones are: get, post, put, delete, copy, patch
}
module.exports = exports = index

7
app/views/errors/400.pug Normal file
View File

@@ -0,0 +1,7 @@
extends error
block head
title Bad Request | #{_app ? _app.name : 'Flitter'}
block message
p.flitter-name 400: Bad Request

7
app/views/errors/401.pug Normal file
View File

@@ -0,0 +1,7 @@
extends error
block head
title Access Denied | #{_app ? _app.name : 'Flitter'}
block message
p.flitter-name 401: Access Denied

7
app/views/errors/403.pug Normal file
View File

@@ -0,0 +1,7 @@
extends error
block head
title Forbidden | #{_app ? _app.name : 'Flitter'}
block message
p.flitter-name 403: Forbidden

7
app/views/errors/404.pug Normal file
View File

@@ -0,0 +1,7 @@
extends error
block head
title Not Found | #{_app ? _app.name : 'Flitter'}
block message
p.flitter-name 404: Not Found

9
app/views/errors/418.pug Normal file
View File

@@ -0,0 +1,9 @@
extends error
block head
title I'm a Teapot | #{_app ? _app.name : 'Flitter'}
block message
p.flitter-name
a(href='https://en.wikipedia.org/wiki/HTTP_418') 418: I'm a Teapot
p.flitter-name Thank you for using Flitter. How'd you get here, anyway?

7
app/views/errors/500.pug Normal file
View File

@@ -0,0 +1,7 @@
extends error
block head
title Internal Server Error | #{_app ? _app.name : 'Flitter'}
block message
p.flitter-name 500: Internal Server Error

View File

@@ -0,0 +1,47 @@
html
head
title Uh-Oh! | #{_app ? _app.name : 'Flitter'}
style(type="text/css").
@import url('https://fonts.googleapis.com/css?family=Rajdhani');
@import url('https://fonts.googleapis.com/css?family=Oxygen+Mono');
html,
body {
background-color: #c7dbdf;
font-family: "Rajdhani",sans-serif;
padding-left: 2%;
padding-top: 2%;
}
p {
font-family: "Oxygen Mono",sans-serif;
font-size: 14pt;
}
body
h1 Error: #{error ? error.message : (message ? message : 'An unknown error has occurred.')}
h3 Status: #{error ? error.status : (status ? status : 500)}
h4#errmsg
if error
p !{error.stack.replace(/\n/g, '<br>')}
script.
const errors = [
'Insert your Windows installation disc and restart your computer.',
'I am a teapot.',
'Printing not supported on this printer.',
'Keyboard not found. Press F1 to continue.',
'Bailing out. You\'re on your own. Good luck.',
'A team of highly trained monkeys is on its way.',
'Well.... something happened.',
'Beats the hell out of me, but something went wrong.',
'Yeaaaaah... if you could, like, not, that\'d be great.',
'I\'m fine. Everything is fine.',
'Blocked by Windows Parental Controls.',
'This is not the bug you\'re looking for.',
'Houston, we have a problem.',
'I don\'t think we\'re in Kansas anymore...',
'Please enable ActiveX to continue. ;)',
'Your PC ran into a wall.',
'Are you on drugs?',
'Error: Success',
]
document.getElementById('errmsg').innerHTML = errors[Math.floor(Math.random()*errors.length)]

View File

@@ -0,0 +1,33 @@
html
head
block head
style(type="text/css").
@import url('https://fonts.googleapis.com/css?family=Rajdhani');
html,
body {
height: 100%;
overflow-y: hidden;
background-color: #c7dbdf;
}
.flitter-container {
height: 60%;
display: flex;
align-items: center;
justify-content: center;
}
.flitter-image {
height: 150px;
}
.flitter-name {
font-family: "Rajdhani";
font-size: 50pt;
margin-left: 35px;
color: #00323d;
}
body
.flitter-container
img.flitter-image(src="/assets/flitter.png")
block message

46
app/views/welcome.pug Normal file
View File

@@ -0,0 +1,46 @@
html
head
title #{T('welcome')} | #{_app.name}
style(type="text/css").
@import url('https://fonts.googleapis.com/css?family=Rajdhani');
html,
body {
height: 100%;
overflow-y: hidden;
background-color: #c7dbdf;
}
.flitter-container {
height: 60%;
display: flex;
align-items: center;
justify-content: center;
}
.flitter-image {
height: 150px;
}
.flitter-name {
font-family: "Rajdhani";
font-size: 50pt;
margin-left: 35px;
color: #00323d;
text-decoration: none;
}
.flitter-text {
font-family: "Rajdhani";
font-size: 24pt;
color: #00323d;
}
body
.flitter-container
img.flitter-image(src="/assets/flitter.png")
a.flitter-name(href="https://flitter.garrettmills.dev/" target="_blank") #{T('powered_by_flitter')}
if user
.flitter-container
p.flitter-text #{T('welcome')}, #{user.uid}! <a href="/auth/logout">#{T('log_out')}</a>
else
.flitter-container
p.flitter-text #{T('new_to_flitter')} <a href="https://flitter.garrettmills.dev/" target="_blank">#{T('start_here')}</a>