Compare commits
No commits in common. 'main' and 'release/0.1.0' have entirely different histories.
main
...
release/0.
@ -1,36 +0,0 @@
|
|||||||
import Action from './../../packages/runner/actions/action.ts'
|
|
||||||
import State from './../../packages/runner/_state.ts'
|
|
||||||
import ical from 'node-ical'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getting ics from url and parse it to object
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class IcsExample extends Action {
|
|
||||||
async run() {
|
|
||||||
let response
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = await fetch(this.config.url)
|
|
||||||
} catch(error) {
|
|
||||||
throw new Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if code is 200
|
|
||||||
if (response && response.status === 200) {
|
|
||||||
const body = await response.text()
|
|
||||||
const events = ical.sync.parseICS(body)
|
|
||||||
|
|
||||||
if (events) {
|
|
||||||
this.result = events
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IcsExample
|
|
@ -1,24 +0,0 @@
|
|||||||
import Action from './../../packages/runner/actions/action.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getting json from url, parse response and send to console
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class JsonExample extends Action {
|
|
||||||
async run() {
|
|
||||||
const response = await fetch(this.config.url)
|
|
||||||
|
|
||||||
if (response.status == 200) {
|
|
||||||
this.result = await response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(this.result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default JsonExample
|
|
@ -1,25 +0,0 @@
|
|||||||
import { XMLParser } from 'fast-xml-parser'
|
|
||||||
import Action from './../../packages/runner/actions/action.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getting rss feed from url, parse response and send to console
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class RssExample extends Action {
|
|
||||||
async run() {
|
|
||||||
const response = await fetch(this.config.url)
|
|
||||||
const body = await response.text()
|
|
||||||
|
|
||||||
const parser = new XMLParser()
|
|
||||||
this.result = parser.parse(body)
|
|
||||||
|
|
||||||
console.log(this.result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RssExample
|
|
@ -1,5 +0,0 @@
|
|||||||
name: "Lorem Ipsum RSS"
|
|
||||||
url: "https://lorem-rss.herokuapp.com/feed"
|
|
||||||
cron: "0 1 * * *"
|
|
||||||
actions:
|
|
||||||
- class: "RssExample"
|
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"/public/js/spritemap.js": "/public/js/spritemap.js?id=2dda73ecee3bb668b395026efda6524c",
|
||||||
|
"/public/js/app.js": "/public/js/app.js?id=33b6f39f449c765b8c7674ad6a35b92e",
|
||||||
|
"/public/css/styles.css": "/public/css/styles.css?id=72a43d98017bdbcb83928c41f6289210"
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
|||||||
|
import * as riot from 'riot'
|
||||||
|
|
||||||
|
import AppSidebar from './components/sidebar.riot'
|
||||||
|
|
||||||
|
import AppTasks from './components/tasks.riot'
|
||||||
|
import AppTaskButton from './components/task-new.riot'
|
||||||
|
import AppTaskForm from './components/task-form.riot'
|
||||||
|
|
||||||
|
import AppNotification from './components/notification.riot'
|
||||||
|
|
||||||
|
// register components
|
||||||
|
riot.register('app-sidebar', AppSidebar)
|
||||||
|
riot.register('app-tasks', AppTasks)
|
||||||
|
riot.register('app-task-button', AppTaskButton)
|
||||||
|
riot.register('app-task-form', AppTaskForm)
|
||||||
|
|
||||||
|
riot.register('app-notification', AppNotification)
|
||||||
|
|
||||||
|
// mount components
|
||||||
|
riot.mount('app-sidebar')
|
||||||
|
riot.mount('app-tasks')
|
||||||
|
riot.mount('app-task-button')
|
||||||
|
riot.mount('app-task-form')
|
||||||
|
|
||||||
|
riot.mount('app-notification')
|
@ -0,0 +1 @@
|
|||||||
|
riot = require('riot')
|
@ -0,0 +1,15 @@
|
|||||||
|
<app-loading>
|
||||||
|
<div class="loading-wrapper" if={ props.loading }>
|
||||||
|
<div class="loading">
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</app-loading>
|
@ -0,0 +1,115 @@
|
|||||||
|
<app-notification>
|
||||||
|
<div class="toast-wrapper toast-wrapper--right" if={ state.items.length > 0 }>
|
||||||
|
<div
|
||||||
|
id={ item.id } class={ item.classes.join(' ') }
|
||||||
|
each={ item in state.items }
|
||||||
|
onclick={ (event) => { this.handleClick(event, item) } }>
|
||||||
|
|
||||||
|
<div class="toast__body">
|
||||||
|
{ item.message }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import notificationStore from './../stores/notification'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* notification
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Björn Hase
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.tentakelfabrik.de/herrhase/shiny-dashboard
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state: {
|
||||||
|
items: [],
|
||||||
|
timeout: 2500
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* on mounted
|
||||||
|
*
|
||||||
|
* @param {object} props
|
||||||
|
* @param {object} state
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onMounted(props, state)
|
||||||
|
{
|
||||||
|
// adding service for notifications and listen to "update"
|
||||||
|
notificationStore.on('update', (item) => {
|
||||||
|
|
||||||
|
// adding attributes
|
||||||
|
item.id = 'toast-' + uuidv4()
|
||||||
|
item.classes = [
|
||||||
|
'toast',
|
||||||
|
'toast--' + item.type
|
||||||
|
]
|
||||||
|
|
||||||
|
// create timeout to remove notification
|
||||||
|
item.timeout = setTimeout(() => {
|
||||||
|
this.removeItem(item)
|
||||||
|
}, this.state.timeout)
|
||||||
|
|
||||||
|
this.state.items.push(item)
|
||||||
|
this.update()
|
||||||
|
|
||||||
|
// add animation
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.$('#' + item.id).classList.add('toast--animation')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove single item
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} item
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
removeItem(item)
|
||||||
|
{
|
||||||
|
// adding event if animationend remove html element
|
||||||
|
this.$('#' + item.id).addEventListener('transitionend', () => {
|
||||||
|
|
||||||
|
// find item in state and remove it
|
||||||
|
for (let i = 0; i < this.state.items.length; i++) {
|
||||||
|
if (this.state.items[i].id === item.id) {
|
||||||
|
clearTimeout(this.state.items[i].timeout)
|
||||||
|
this.state.items.splice(i, 1)
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
|
||||||
|
// add animation
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.$('#' + item.id).classList.remove('toast--animation')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove item by clicked on it
|
||||||
|
*
|
||||||
|
* @param {[type]} event
|
||||||
|
* @param {[type]} item
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleClick(event, item)
|
||||||
|
{
|
||||||
|
this.removeItem(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</app-notification>
|
@ -0,0 +1,88 @@
|
|||||||
|
<app-sidebar>
|
||||||
|
<div class={ getCssClasses() }>
|
||||||
|
<div class="sidebar__inner">
|
||||||
|
|
||||||
|
<!-- header -->
|
||||||
|
<div class="bar">
|
||||||
|
<div class="bar__main">
|
||||||
|
<slot name="title" />
|
||||||
|
</div>
|
||||||
|
<div class="bar__end">
|
||||||
|
<button class="button button--transparent" type="button" onclick={ (event) => { handleClose(event) } }>
|
||||||
|
<svg class="icon fill-danger fill-text-hover" aria-hidden="true">
|
||||||
|
<use xlink:href="/symbol-defs.svg#icon-close"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- body -->
|
||||||
|
<div class="sidebar__body">
|
||||||
|
<slot name="form" />
|
||||||
|
<app-loading loading={ props.loading }></app-loading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- footer -->
|
||||||
|
<div class="sidebar__footer">
|
||||||
|
<button class="button m-bottom-0" type="submit" form="{ props.formId }" disabled={ props.loading }>
|
||||||
|
Save
|
||||||
|
<svg class="icon fill-success p-left-3" aria-hidden="true">
|
||||||
|
<use xlink:href="/symbol-defs.svg#icon-check"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="button m-bottom-0" type="submit" form="{ props.formId }" disabled={ props.loading } close>
|
||||||
|
Save and Close
|
||||||
|
<svg class="icon fill-success p-left-3" aria-hidden="true">
|
||||||
|
<use xlink:href="/symbol-defs.svg#icon-arrow-right"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import * as riot from 'riot'
|
||||||
|
|
||||||
|
import AppLoading from './loading.riot'
|
||||||
|
riot.register('app-loading', AppLoading)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleClose()
|
||||||
|
{
|
||||||
|
this.props.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getCssClasses()
|
||||||
|
{
|
||||||
|
const classes = [
|
||||||
|
'sidebar'
|
||||||
|
]
|
||||||
|
|
||||||
|
if (this.props.open === true) {
|
||||||
|
classes.push('sidebar--open')
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</app-sidebar>
|
@ -0,0 +1,259 @@
|
|||||||
|
<app-task-form>
|
||||||
|
|
||||||
|
<app-sidebar form-id="app-task-form" open={ state.isOpen } close={ () => { handleClose() } } loading={ state.isLoading }>
|
||||||
|
|
||||||
|
<!-- slot:title -->
|
||||||
|
<span slot="title">
|
||||||
|
<virtual if={ state.current._id }>
|
||||||
|
Edit Task { state.current.name }
|
||||||
|
</virtual>
|
||||||
|
<virtual if={ !state.current._id }>
|
||||||
|
New Task
|
||||||
|
</virtual>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- slot:header -->
|
||||||
|
<form id="app-task-form" class="form" slot="form" onsubmit={ (event) => { state.isLoading = true; update(); state.validator.submit(event) } }>
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">
|
||||||
|
name
|
||||||
|
<input class="field-text" name="name" type="text" value="{ state.current.name }" />
|
||||||
|
<field-error name="name"></field-error>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">
|
||||||
|
url
|
||||||
|
<input class="field-text" name="url" type="text" value="{ state.current.url }" />
|
||||||
|
<field-error name="url"></field-error>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">
|
||||||
|
requestHandlers
|
||||||
|
<select class="field-choice" name="requestHandler">
|
||||||
|
<option></option>
|
||||||
|
<option value="{ requestHandler.file }" each={ requestHandler in state.requestHandlers } selected={ state.current.requestHandler && requestHandler.file === state.current.requestHandler.file }>
|
||||||
|
{ requestHandler.name }
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<field-error name="requestHandlers"></field-error>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">
|
||||||
|
actionHandlers
|
||||||
|
<select class="field-choice" name="action">
|
||||||
|
<option></option>
|
||||||
|
<option value="{ actionHandler.file }" each={ actionHandler in state.actionHandlers } selected={ state.current.actionHandler && actionHandler.file === state.current.actionHandler.file }>
|
||||||
|
{ actionHandler.name }
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<field-error name="actionHandlers"></field-error>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">
|
||||||
|
options
|
||||||
|
<input type="text" name="options" class="field-text" value="{ JSON.stringify(state.current.options) }" />
|
||||||
|
<field-error name="options"></field-error>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">
|
||||||
|
timer
|
||||||
|
<input type="text" name="timer" class="field-text" value="{ state.current.timer }" />
|
||||||
|
<field-error name="timer"></field-error>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</app-sidebar>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import * as riot from 'riot'
|
||||||
|
|
||||||
|
import FormValidator from '@tiny-components/validator/src/formValidator.js'
|
||||||
|
|
||||||
|
// stores
|
||||||
|
import taskFormStore from './../stores/taskForm.js'
|
||||||
|
import notificationStore from './../stores/notification'
|
||||||
|
|
||||||
|
// mixins
|
||||||
|
import sidebar from './../mixins/sidebar.js'
|
||||||
|
|
||||||
|
import FieldError from '@tiny-components/validator/src/fieldError.riot'
|
||||||
|
riot.register('field-error', FieldError)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return {
|
||||||
|
|
||||||
|
...sidebar, // adding basic funtion for sidebar
|
||||||
|
|
||||||
|
state: {
|
||||||
|
requestHandlers: [],
|
||||||
|
validator: undefined
|
||||||
|
},
|
||||||
|
|
||||||
|
onBeforeMount()
|
||||||
|
{
|
||||||
|
this.resetCurrent()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onMounted()
|
||||||
|
{
|
||||||
|
// creating formValidator
|
||||||
|
this.state.validator = new FormValidator(this.$('.form'), {
|
||||||
|
'name': {
|
||||||
|
'presence': true
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'presence': true
|
||||||
|
},
|
||||||
|
'requestHandler': {
|
||||||
|
'presence': true
|
||||||
|
},
|
||||||
|
'action': {
|
||||||
|
'presence': true
|
||||||
|
},
|
||||||
|
'timer': {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// adding on success
|
||||||
|
this.state.validator.onSuccess((event, data) => {
|
||||||
|
this.handleSuccess(event, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
// adding on success
|
||||||
|
this.state.validator.onError((event, data) => {
|
||||||
|
this.state.isLoading = false
|
||||||
|
|
||||||
|
// add notification
|
||||||
|
notificationStore.danger('Error! Check your input!')
|
||||||
|
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
|
||||||
|
//
|
||||||
|
taskFormStore.on('open', (data) => {
|
||||||
|
|
||||||
|
this.resetCurrent()
|
||||||
|
this.state.isOpen = true
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
this.state.current = data
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.getRequestHandlers()
|
||||||
|
this.getActionHandlers()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
resetCurrent()
|
||||||
|
{
|
||||||
|
this.state.current = {
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
requestHandlers: '',
|
||||||
|
actionHandlers: '',
|
||||||
|
options: {
|
||||||
|
|
||||||
|
},
|
||||||
|
timer: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getting available RequestHandlers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getRequestHandlers()
|
||||||
|
{
|
||||||
|
fetch('/api/v1/handler/request', {
|
||||||
|
'method': 'GET'
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
this.state.requestHandlers = response.data
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getting available ActionHandlers
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getActionHandlers()
|
||||||
|
{
|
||||||
|
fetch('/api/v1/handler/action', {
|
||||||
|
'method': 'GET'
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
this.state.actionHandlers = response.data
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send data to server
|
||||||
|
*
|
||||||
|
* @param {object} event
|
||||||
|
* @param {object} data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleSuccess(event, data)
|
||||||
|
{
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
fetch('/api/v1/task', {
|
||||||
|
'method': 'POST',
|
||||||
|
'body': JSON.stringify(data),
|
||||||
|
'headers': {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
|
||||||
|
// stop loading
|
||||||
|
this.state.isLoading = false
|
||||||
|
|
||||||
|
// add id to current
|
||||||
|
this.state.current.id = response.data.id
|
||||||
|
this.update()
|
||||||
|
}).catch((error) => {
|
||||||
|
|
||||||
|
// stop loading
|
||||||
|
this.state.isLoading = false
|
||||||
|
|
||||||
|
// show error message
|
||||||
|
notificationStore.danger('Error! Server has a Error, Request can not proceed!')
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</app-task-form>
|
@ -0,0 +1,54 @@
|
|||||||
|
<app-task-button>
|
||||||
|
<button class="button m-bottom-0 m-top-5" onclick={ (event) => { handleOpen(event) } }>
|
||||||
|
<svg class="icon fill-text fill-text-contrast-hover m-top-1 p-right-2" aria-hidden="true">
|
||||||
|
<use xlink:href="/symbol-defs.svg#icon-close"></use>
|
||||||
|
</svg>
|
||||||
|
{ state.text }
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import taskFormStore from './../stores/taskForm.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle open and close of form for tasks
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Björn Hase, <me@herr-hase.wtf>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state: {
|
||||||
|
text: 'new'
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onMounted()
|
||||||
|
{
|
||||||
|
// if props for text is set
|
||||||
|
if (this.props.text) {
|
||||||
|
this.state.text = this.props.text
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* trigger open in storage
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} event
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleOpen(event, data = undefined)
|
||||||
|
{
|
||||||
|
taskFormStore.open(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</app-task-button>
|
@ -0,0 +1,153 @@
|
|||||||
|
<app-tasks>
|
||||||
|
<div class="tasks">
|
||||||
|
<table class="table table--stripped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td class="table__th">
|
||||||
|
state
|
||||||
|
</td>
|
||||||
|
<th class="table__th">
|
||||||
|
name
|
||||||
|
</th>
|
||||||
|
<th class="table__th">
|
||||||
|
url
|
||||||
|
</th>
|
||||||
|
<th class="table__th">
|
||||||
|
requestHandler
|
||||||
|
</th>
|
||||||
|
<th class="table__th">
|
||||||
|
actions
|
||||||
|
</th>
|
||||||
|
<th class="table__th">
|
||||||
|
cron
|
||||||
|
</th>
|
||||||
|
<th class="table__th"></th>
|
||||||
|
<tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr if={ state.tasks.length > 0 } each={ task in state.tasks }>
|
||||||
|
<td class="table__td">
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td class="table__td">
|
||||||
|
{ task.name }
|
||||||
|
</td>
|
||||||
|
<td class="table__td">
|
||||||
|
{ task.url }
|
||||||
|
</td>
|
||||||
|
<td class="table__td">
|
||||||
|
{ task.requestHandler }
|
||||||
|
</td>
|
||||||
|
<td class="table__td">
|
||||||
|
<virtual each={ action in task.actions }>
|
||||||
|
<span>
|
||||||
|
{ action.className }
|
||||||
|
</span>
|
||||||
|
<span if={ actions.options }>
|
||||||
|
{ JSON.stringify(action.options) }
|
||||||
|
</span>
|
||||||
|
</virtual>
|
||||||
|
</td>
|
||||||
|
<td class="table__td">
|
||||||
|
{ task.cron }
|
||||||
|
</td>
|
||||||
|
<td class="table__td">
|
||||||
|
<button class="button">
|
||||||
|
Pause
|
||||||
|
</button>
|
||||||
|
<button class="button" onclick={ (event) => { handleEdit(event, task) } }>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button class="button" onclick={ (event) => { handleDelete(event, task) } }>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr if={ state.tasks.length === 0 }>
|
||||||
|
<td class="table__td center" colspan="6">
|
||||||
|
Nothing found
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
// stores
|
||||||
|
import taskFormStore from './../stores/taskForm.js'
|
||||||
|
import notificationStore from './../stores/notification'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show all tasks
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default
|
||||||
|
{
|
||||||
|
state: {
|
||||||
|
tasks: []
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onMounted()
|
||||||
|
{
|
||||||
|
this.getTasks()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getTasks()
|
||||||
|
{
|
||||||
|
fetch('/api/v1/task')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
this.state.tasks = response.data
|
||||||
|
this.update()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete
|
||||||
|
*
|
||||||
|
* @param {object} event
|
||||||
|
* @param {object} task
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleDelete(event, task)
|
||||||
|
{
|
||||||
|
fetch('/api/v1/task/' + task._id, {
|
||||||
|
'method': 'DELETE'
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
notificationStore.success('Deleted ' + response.data.name + '!')
|
||||||
|
this.getTasks()
|
||||||
|
})
|
||||||
|
.catch((errors) => {
|
||||||
|
notificationStore.success('Error! ' + response.data.name + ' could not deleted!')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* edit task, trigger form taskForm
|
||||||
|
*
|
||||||
|
* @param {object} event
|
||||||
|
* @param {object} task
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleEdit(event, task)
|
||||||
|
{
|
||||||
|
taskFormStore.open(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</app-tasks>
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state: {
|
||||||
|
isOpen: false,
|
||||||
|
isLoading: false
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleClose()
|
||||||
|
{
|
||||||
|
this.state.isOpen = false
|
||||||
|
this.update()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
import observable from '@riotjs/observable'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NotificationService
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export default observable({
|
||||||
|
|
||||||
|
SUCCESS: 'success',
|
||||||
|
DANGER: 'danger',
|
||||||
|
INFO: 'info',
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
success(message) {
|
||||||
|
this._add(message, this.SUCCESS)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
danger(message) {
|
||||||
|
this._add(message, this.DANGER)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
info(message) {
|
||||||
|
this._add(message, this.INFO)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} message [description]
|
||||||
|
* @param {[type]} type [description]
|
||||||
|
*/
|
||||||
|
_add(message, type) {
|
||||||
|
this.trigger('update', {
|
||||||
|
message: message,
|
||||||
|
type: type
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Björn Hase
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import observable from '@riotjs/observable'
|
||||||
|
|
||||||
|
export default observable(
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
open(data)
|
||||||
|
{
|
||||||
|
this.trigger('open', data)
|
||||||
|
}
|
||||||
|
})
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "npx mix"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@riotjs/observable": "^4.1.1",
|
||||||
|
"@tiny-components/plain-ui": "^0.5.0",
|
||||||
|
"@tiny-components/validator": "^0.1.0",
|
||||||
|
"got": "^12.0.1",
|
||||||
|
"riot": "^6.1.2",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@riotjs/webpack-loader": "^6.0.0",
|
||||||
|
"laravel-mix": "^6.0.43",
|
||||||
|
"laravel-mix-purgecss": "^6.0.0",
|
||||||
|
"sass": "^1.49.9",
|
||||||
|
"sass-loader": "^12.6.0",
|
||||||
|
"svg-spritemap-webpack-plugin": "^4.4.0"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
// format list of errors
|
||||||
|
.field-error {
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 0 1em;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
.loading-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #ffffff45;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
@import
|
||||||
|
|
||||||
|
'@tiny-components/plain-ui/src/scss/plain-ui',
|
||||||
|
|
||||||
|
'components/field-error',
|
||||||
|
'components/loading';
|
@ -0,0 +1,22 @@
|
|||||||
|
{% layout 'layout.liquid' %}
|
||||||
|
|
||||||
|
{% block app_main %}
|
||||||
|
<div class="container-full">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="col-12">
|
||||||
|
<app-task-button></app-task-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="col-12">
|
||||||
|
<app-tasks></app-tasks>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<app-task-form></app-task-form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script async src="/js/app.js"></script>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,70 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en_EN">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>
|
||||||
|
Super Hog
|
||||||
|
</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<link href="/css/styles.css" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
{% block head %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
{% block app_header %}
|
||||||
|
<div class="bar">
|
||||||
|
<div class="bar__start">
|
||||||
|
<h1 class="m-top-4 m-bottom-4 h4">
|
||||||
|
Super Hog
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<noscript>
|
||||||
|
<div class="container-full">
|
||||||
|
<div class="grid justify-center">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="panel panel--border-highlight border-color-danger m-bottom-4">
|
||||||
|
Only works with Javascript!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
|
|
||||||
|
{% block app_main %}{% endblock %}
|
||||||
|
<app-notification></app-notification>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container-full">
|
||||||
|
<div class="grid justify-center">
|
||||||
|
<div class="col-12">
|
||||||
|
<hr / class="m-top-8">
|
||||||
|
<div class="group">
|
||||||
|
<div class="group__item">
|
||||||
|
Published under
|
||||||
|
<strong>
|
||||||
|
MIT License
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const csrfToken = '{{ csrfToken }}'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% block script %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,15 @@
|
|||||||
|
{% layout 'layout.liquid' %}
|
||||||
|
|
||||||
|
{% block app_main %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="grid justify-center">
|
||||||
|
<div class="col-12 col-md-8">
|
||||||
|
<app-login></app-login>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script async src="/js/app.js"></script>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,81 @@
|
|||||||
|
const mix = require('laravel-mix')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
require('laravel-mix-purgecss')
|
||||||
|
|
||||||
|
// plugins
|
||||||
|
const SvgSpritemapPlugin = require('svg-spritemap-webpack-plugin')
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Mix Asset Management
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Mix provides a clean, fluent API for defining some Webpack build steps
|
||||||
|
| for your Laravel applications. By default, we are compiling the CSS
|
||||||
|
| file for the application as well as bundling up all the JS files.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
mix.webpackConfig({
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.riot$/,
|
||||||
|
use: [{
|
||||||
|
loader: '@riotjs/webpack-loader',
|
||||||
|
options: {
|
||||||
|
hot: false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]},
|
||||||
|
plugins: [
|
||||||
|
new SvgSpritemapPlugin('node_modules/@tiny-components/plain-ui/src/icons/mono-icons/svg/*.svg', {
|
||||||
|
output: {
|
||||||
|
filename: 'public/symbol-defs.svg',
|
||||||
|
chunk: {
|
||||||
|
keep: true
|
||||||
|
},
|
||||||
|
svgo: {
|
||||||
|
plugins: [{
|
||||||
|
name: 'convertStyleToAttrs',
|
||||||
|
active: true
|
||||||
|
},{
|
||||||
|
name: 'removeStyleElement',
|
||||||
|
active: true
|
||||||
|
}, {
|
||||||
|
name: 'removeAttrs',
|
||||||
|
params: {
|
||||||
|
attrs: 'fill'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sprite: {
|
||||||
|
prefix: 'icon-'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
mix
|
||||||
|
.setPublicPath('../../')
|
||||||
|
.js('js/app.js', 'public/js')
|
||||||
|
.sass('scss/styles.scss', 'public/css')
|
||||||
|
.purgeCss({
|
||||||
|
extend: {
|
||||||
|
content: [
|
||||||
|
path.join(__dirname, 'js/**/*.riot'),
|
||||||
|
path.join(__dirname, 'views/*.liquid')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.options({
|
||||||
|
terser: {
|
||||||
|
extractComments: false,
|
||||||
|
},
|
||||||
|
processCssUrls: false
|
||||||
|
})
|
||||||
|
.copyDirectory('node_modules/@tiny-components/plain-ui/src/fonts/**', '../../public/css')
|
||||||
|
.version()
|
@ -1,4 +0,0 @@
|
|||||||
import dotenv from 'dotenv'
|
|
||||||
|
|
||||||
// getting .env
|
|
||||||
dotenv.config({ path: path.join(path.resolve(), '/.env') })
|
|
@ -1,48 +0,0 @@
|
|||||||
import { JSONFilePreset } from 'lowdb/node'
|
|
||||||
import merge from 'deepmerge'
|
|
||||||
|
|
||||||
const db = await JSONFilePreset('./storage/db.json', { runs: [] })
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Db {
|
|
||||||
|
|
||||||
public constructor(slug) {
|
|
||||||
this.slug = slug
|
|
||||||
this.data = db.data.runs.find((runs) => runs.slug === this.slug)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async get() {
|
|
||||||
if (this.data === undefined) {
|
|
||||||
this.data = {
|
|
||||||
'slug': this.slug,
|
|
||||||
'date_created_at': dayjs().toISOString(),
|
|
||||||
'date_run_started_at': dayjs().toISOString()
|
|
||||||
}
|
|
||||||
|
|
||||||
db.data.runs.push(run)
|
|
||||||
await db.write()
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.data
|
|
||||||
}
|
|
||||||
|
|
||||||
public async update(data) {
|
|
||||||
db.data.runs.find((run, index) => {
|
|
||||||
if (run.slug === this.slug) {
|
|
||||||
db.data.runs[index] = merge(db.data.runs[index], data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await db.write()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Db
|
|
@ -1,75 +0,0 @@
|
|||||||
import State from './_state.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Docket
|
|
||||||
*
|
|
||||||
* Is used to hold all data and configs that run through the actions
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Docket {
|
|
||||||
|
|
||||||
// config for action
|
|
||||||
private config: object
|
|
||||||
|
|
||||||
// data
|
|
||||||
private data: object
|
|
||||||
private options: object
|
|
||||||
private db: object
|
|
||||||
private states: array
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param object config
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public constructor(config: object, db: object) {
|
|
||||||
this.config = config
|
|
||||||
this.db = db
|
|
||||||
this.states = []
|
|
||||||
}
|
|
||||||
|
|
||||||
public getData() {
|
|
||||||
return this.data
|
|
||||||
}
|
|
||||||
|
|
||||||
public setData(data: object) {
|
|
||||||
return this.data = data
|
|
||||||
}
|
|
||||||
|
|
||||||
public setOptions(options): object {
|
|
||||||
this.options = options
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConfig(): object {
|
|
||||||
return this.config
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDb(): object {
|
|
||||||
return this.db
|
|
||||||
}
|
|
||||||
|
|
||||||
public addState(value: State) {
|
|
||||||
this.states.push(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasState(value: State) {
|
|
||||||
let result = false
|
|
||||||
|
|
||||||
for (let index in this.states) {
|
|
||||||
if (this.states[index] == value) {
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Docket
|
|
@ -1,65 +0,0 @@
|
|||||||
import dayjs from 'dayjs'
|
|
||||||
import Db from './_db.ts'
|
|
||||||
import Docket from './_docket.ts'
|
|
||||||
|
|
||||||
import { resolveActionClass } from './helpers/resolver.ts'
|
|
||||||
import logger from './helpers/logger.ts'
|
|
||||||
import State from './_state.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* run through a single config, getting each action with config
|
|
||||||
* and run them, the docket will be used to hold data and configs
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
async function run(config: object) {
|
|
||||||
|
|
||||||
let db = new Db(config.slug)
|
|
||||||
let docket = new Docket(config, db)
|
|
||||||
|
|
||||||
// update db
|
|
||||||
await db.update({
|
|
||||||
'date_started_at': dayjs().toISOString()
|
|
||||||
})
|
|
||||||
|
|
||||||
logger(config.slug).info('has started')
|
|
||||||
|
|
||||||
for (const actionConfig of config.actions) {
|
|
||||||
|
|
||||||
// resolve action class
|
|
||||||
const ActionClass = await import(resolveActionClass(actionConfig.class))
|
|
||||||
|
|
||||||
// options are exists, add to docket
|
|
||||||
if (actionConfig.hasOwnProperty('options')) {
|
|
||||||
docket.setOptions(action.options)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const action = new ActionClass.default(docket)
|
|
||||||
|
|
||||||
logger(config.slug).info('action / ' + actionConfig.class)
|
|
||||||
|
|
||||||
await action.run()
|
|
||||||
docket = action.getDocket()
|
|
||||||
|
|
||||||
} catch(error) {
|
|
||||||
logger(config.slug).error('action / ' + actionConfig.class + ' / ' + error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(config.slug).info('has finished')
|
|
||||||
|
|
||||||
// update db only state FINISHED is set
|
|
||||||
if (docket.hasState(State.FINISHED)) {
|
|
||||||
await db.update({
|
|
||||||
'date_finished_at': dayjs().toISOString()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return docket
|
|
||||||
}
|
|
||||||
|
|
||||||
export default run
|
|
@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum State {
|
|
||||||
FINISHED
|
|
||||||
}
|
|
||||||
|
|
||||||
export default State
|
|
@ -1,27 +0,0 @@
|
|||||||
import logger from './helpers/logger.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Webhook
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Webhook {
|
|
||||||
static send(message: string) {
|
|
||||||
|
|
||||||
const query = new URLSearchParams({
|
|
||||||
'message': message
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
fetch(process.env.WEBHOOK_URL + '?' + query.toString())
|
|
||||||
} catch(error) {
|
|
||||||
logger().error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Webhook
|
|
@ -1,46 +0,0 @@
|
|||||||
import ActionInterface from './actionInterface.ts'
|
|
||||||
import Docket from './../docket.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Action implements ActionInterface {
|
|
||||||
|
|
||||||
private docket: Docket
|
|
||||||
private data: object
|
|
||||||
private result: object
|
|
||||||
private options: object
|
|
||||||
private config: object
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public constructor(docket: Docket, options: object = {}) {
|
|
||||||
this.docket = docket
|
|
||||||
this.data = docket.getData()
|
|
||||||
|
|
||||||
// current data will be set as data
|
|
||||||
this.result = this.data
|
|
||||||
|
|
||||||
this.options = options
|
|
||||||
this.config = docket.getConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set result as data
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public getDocket() {
|
|
||||||
this.docket.setData(this.result)
|
|
||||||
return this.docket
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Action
|
|
@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Interface for Action
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
interface ActionInterface {
|
|
||||||
async run(): any
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ActionInterface
|
|
@ -0,0 +1,14 @@
|
|||||||
|
import Interface from 'es6-interface'
|
||||||
|
import Action from './../../actions/action.js'
|
||||||
|
|
||||||
|
class MoveFile extends Action
|
||||||
|
{
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
for (const item of this.data.rss.channel.item) {
|
||||||
|
console.log(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MoveFile
|
@ -0,0 +1,30 @@
|
|||||||
|
import Interface from 'es6-interface'
|
||||||
|
import https from 'https'
|
||||||
|
|
||||||
|
import ActionInterface from './actionInterface.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Action extends Interface(ActionInterface)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} data
|
||||||
|
* @param {[type]} source
|
||||||
|
*/
|
||||||
|
constructor(source, data, options)
|
||||||
|
{
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.source = source
|
||||||
|
this.data = data
|
||||||
|
this.options = options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Action
|
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ActionInterface = {
|
||||||
|
run: function()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ActionInterface
|
@ -0,0 +1,58 @@
|
|||||||
|
import got from 'got'
|
||||||
|
import url from 'url'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
import { createWriteStream } from 'fs'
|
||||||
|
|
||||||
|
import Action from './action.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @extends Action
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DownloadPodcast extends Action
|
||||||
|
{
|
||||||
|
async run()
|
||||||
|
{
|
||||||
|
// count of files
|
||||||
|
let files = 0
|
||||||
|
|
||||||
|
// errors
|
||||||
|
let errors = []
|
||||||
|
|
||||||
|
for (let item of this.data.rss.channel.item)
|
||||||
|
{
|
||||||
|
// gettin
|
||||||
|
const pubDate = new Date(item.pubDate)
|
||||||
|
|
||||||
|
// check for new entries
|
||||||
|
if (pubDate >= new Date(this.source.last_run_at))
|
||||||
|
{
|
||||||
|
const parsedUrl = url.parse(item.link)
|
||||||
|
const filename = decodeURIComponent(path.basename(parsedUrl.pathname))
|
||||||
|
|
||||||
|
const downloadStream = got.stream(item.link)
|
||||||
|
const fileWriterStream = createWriteStream(this.options.destination + '/' + filename)
|
||||||
|
|
||||||
|
downloadStream
|
||||||
|
.on('error', (error) => {
|
||||||
|
console.error(`Download failed: ${error.message}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
fileWriterStream
|
||||||
|
.on('error', (error) => {
|
||||||
|
console.error(`Could not write file to system: ${error.message}`)
|
||||||
|
})
|
||||||
|
.on('finish', () => {
|
||||||
|
files++
|
||||||
|
})
|
||||||
|
|
||||||
|
await downloadStream.pipe(fileWriterStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DownloadPodcast
|
@ -0,0 +1,34 @@
|
|||||||
|
import got from 'got'
|
||||||
|
import { XMLParser } from 'fast-xml-parser'
|
||||||
|
|
||||||
|
import RequestHandler from './requestHandler.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class JsonHandler extends RequestHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* getting rss feed from url
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async send()
|
||||||
|
{
|
||||||
|
const buffer = await got(this.source.url, {
|
||||||
|
responseType: 'buffer',
|
||||||
|
resolveBodyOnly: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const parser = new XMLParser()
|
||||||
|
const feed = parser.parse(buffer.toString())
|
||||||
|
|
||||||
|
this.processActions(feed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RssHandler
|
@ -0,0 +1,64 @@
|
|||||||
|
import Interface from 'es6-interface'
|
||||||
|
|
||||||
|
import RequestHandlerInterface from './requestHandlerInterface.js'
|
||||||
|
import ResolverClass from './../helpers/resolverClass.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RequestHandler extends Interface(RequestHandlerInterface)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} source
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor(source)
|
||||||
|
{
|
||||||
|
super()
|
||||||
|
this.source = source
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* process actions that are saved in a source
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async processActions(data)
|
||||||
|
{
|
||||||
|
let errors = false
|
||||||
|
|
||||||
|
this.source.actions.forEach(async (actions) =>
|
||||||
|
{
|
||||||
|
const resolverClass = new ResolverClass('actions')
|
||||||
|
const classPath = resolverClass.find(actions.className)
|
||||||
|
|
||||||
|
// import class from action
|
||||||
|
const Action = await import(classPath)
|
||||||
|
|
||||||
|
// create action an call run
|
||||||
|
const action = new Action.default(this.source, data, actions.options)
|
||||||
|
|
||||||
|
//
|
||||||
|
if (!await action.run())
|
||||||
|
{
|
||||||
|
errors = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// if errors
|
||||||
|
if (errors && this.source.errors < 5) {
|
||||||
|
this.source.errors++
|
||||||
|
} else {
|
||||||
|
this.source.last_run_at = new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RequestHandler
|
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const RequestHandlerInterface = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
send: function() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RequestHandlerInterface
|
@ -0,0 +1,34 @@
|
|||||||
|
import got from 'got'
|
||||||
|
import { XMLParser } from 'fast-xml-parser'
|
||||||
|
|
||||||
|
import RequestHandler from './requestHandler.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RssHandler extends RequestHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* getting rss feed from url
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async send()
|
||||||
|
{
|
||||||
|
const buffer = await got(this.source.url, {
|
||||||
|
responseType: 'buffer',
|
||||||
|
resolveBodyOnly: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const parser = new XMLParser()
|
||||||
|
const feed = parser.parse(buffer.toString())
|
||||||
|
|
||||||
|
this.processActions(feed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RssHandler
|
@ -1,36 +0,0 @@
|
|||||||
import pino from 'pino'
|
|
||||||
import pretty from 'pino-pretty'
|
|
||||||
import dayjs from 'dayjs'
|
|
||||||
import { mkdirSync } from "node:fs"
|
|
||||||
import slug from 'slug'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for logger
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function logger(slug?: string) {
|
|
||||||
|
|
||||||
let destination = './storage/logs/'
|
|
||||||
|
|
||||||
// if name is set, adding name as directory
|
|
||||||
if (slug) {
|
|
||||||
destination += slug + '/'
|
|
||||||
mkdirSync(destination, { recursive: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
destination += dayjs().format('DD-MM-YYYY') + '.log'
|
|
||||||
|
|
||||||
return pino({
|
|
||||||
timestamp: () => {
|
|
||||||
return `, "time":"${new Date(Date.now()).toISOString()}"`
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pino.destination(destination)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default logger
|
|
@ -1,71 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import yaml from 'js-yaml'
|
|
||||||
import slug from 'slug'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* resolve action class
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function resolveActionClass(className) {
|
|
||||||
|
|
||||||
let classPath = path.join(path.resolve(), 'resources/actions/' + className + '.ts')
|
|
||||||
let result = undefined
|
|
||||||
|
|
||||||
if (fs.existsSync(classPath)) {
|
|
||||||
result = classPath
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
throw new Error('Action Class ' + className + ' / ' + classPath + ' not found!')
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* loading all configs from enabled directory
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function resolveEnabledConfig(name?: string) {
|
|
||||||
|
|
||||||
const configs = []
|
|
||||||
const directoryPath = path.join(path.resolve(), 'resources/config')
|
|
||||||
|
|
||||||
// load files from enabled
|
|
||||||
const files = fs.readdirSync(directoryPath + '/enabled')
|
|
||||||
|
|
||||||
for (let index in files) {
|
|
||||||
let file = files[index]
|
|
||||||
|
|
||||||
if (!file.endsWith('.yml')) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name !== undefined && file !== (name + '.yml')) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = yaml.load(fs.readFileSync(directoryPath + '/enabled/' + file))
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
result.slug = slug(result.name)
|
|
||||||
configs.push(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configs
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
resolveActionClass,
|
|
||||||
resolveEnabledConfig
|
|
||||||
}
|
|
@ -0,0 +1,72 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ResolverClass
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} prefix
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor(prefix)
|
||||||
|
{
|
||||||
|
this.prefix = prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {String} className
|
||||||
|
* @param {Boolean} [isCustom=false]
|
||||||
|
* @return {String}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
lookupPath(className, isCustom = false)
|
||||||
|
{
|
||||||
|
let custom = ''
|
||||||
|
|
||||||
|
if (isCustom) {
|
||||||
|
custom = '/custom/'
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.join(path.resolve(), custom + this.prefix + '/' + className + '.js')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} className
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
find(className)
|
||||||
|
{
|
||||||
|
// getting
|
||||||
|
let classPath = this.lookupPath(className, true)
|
||||||
|
|
||||||
|
// results
|
||||||
|
let result = false
|
||||||
|
|
||||||
|
if (fs.existsSync(classPath)) {
|
||||||
|
result = classPath
|
||||||
|
} else {
|
||||||
|
classPath = this.lookupPath(className)
|
||||||
|
|
||||||
|
if (fs.existsSync(classPath)) {
|
||||||
|
result = classPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Class ' + className + ' not found!')
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResolverClass
|
@ -0,0 +1,29 @@
|
|||||||
|
import cron from 'node-cron'
|
||||||
|
|
||||||
|
const tasks = []
|
||||||
|
|
||||||
|
// uuid, schedule, source, requestHandler, actions, state
|
||||||
|
|
||||||
|
// start main cron to check for updates while running
|
||||||
|
//const main = cron.schedule('* * * * *', () => {
|
||||||
|
|
||||||
|
//})
|
||||||
|
|
||||||
|
//main.start()
|
||||||
|
|
||||||
|
import RssHandler from './requestHandlers/rssHandler.js'
|
||||||
|
|
||||||
|
const source = {
|
||||||
|
'name': 'Insert Moin',
|
||||||
|
'url': 'https://steadyhq.com/rss/insertmoin?auth=d37bffc9-9a84-4eed-95f6-3b6cb77c2406',
|
||||||
|
'actions': [{
|
||||||
|
'className': 'downloadPodcast',
|
||||||
|
'options': {
|
||||||
|
'destination': '/home/herrhase/Downloads'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
'last_run_at': '2022-01-16T23:01:00.000Z'
|
||||||
|
}
|
||||||
|
|
||||||
|
const rssHandler = new RssHandler(source)
|
||||||
|
rssHandler.send()
|
@ -1,46 +0,0 @@
|
|||||||
import cron from 'node-cron'
|
|
||||||
|
|
||||||
import { resolveEnabledConfig } from './helpers/resolver.ts'
|
|
||||||
import logger from './helpers/logger.ts'
|
|
||||||
|
|
||||||
import run from './_run.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run all Configs that are in Directory /resources/configs/enabled
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// get all configs from resolveEnabledConfig
|
|
||||||
const configs = resolveEnabledConfig()
|
|
||||||
|
|
||||||
// check if there is any valid config
|
|
||||||
if (configs.length === 0) {
|
|
||||||
throw new Error('No valid config found!')
|
|
||||||
}
|
|
||||||
|
|
||||||
// running through configs
|
|
||||||
for (const index in configs) {
|
|
||||||
|
|
||||||
const config = configs[index]
|
|
||||||
|
|
||||||
// check for cron
|
|
||||||
if (!config.hasOwnProperty('cron')) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* adding task to schedule, using cron
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const task = cron.schedule(config.cron, async() => {
|
|
||||||
try {
|
|
||||||
const docket = await run(config)
|
|
||||||
} catch(error) {
|
|
||||||
logger(config.slug).error(error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Notiication
|
||||||
|
{
|
||||||
|
webhook(url)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
|||||||
import chalk from 'chalk'
|
|
||||||
|
|
||||||
import { resolveEnabledConfig } from './helpers/resolver.ts'
|
|
||||||
import Docket from './docket.ts'
|
|
||||||
import logger from './helpers/logger.ts'
|
|
||||||
|
|
||||||
import run from './_run.ts'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run single Config that is in Directory /resources/configs/enabled
|
|
||||||
*
|
|
||||||
* @author Björn Hase <me@herr-hase.wtf>
|
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
|
||||||
* @link https://git.node001.net/HerrHase/super-hog.git
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const args = process.argv.slice(2)
|
|
||||||
|
|
||||||
if (args[0] === undefined) {
|
|
||||||
console.log(chalk.red('Required name for config'))
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all configs from resolveEnabledConfig
|
|
||||||
const configs = resolveEnabledConfig(args[0])
|
|
||||||
|
|
||||||
// check if there is any valid config
|
|
||||||
if (configs.length === 0) {
|
|
||||||
console.log(chalk.red('Config ' + args[0] + ' not found!'))
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = configs[0]
|
|
||||||
|
|
||||||
try {
|
|
||||||
const docket = await run(config)
|
|
||||||
} catch(error) {
|
|
||||||
logger(config.slug).error(error)
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
import { getDB } from './../db.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Store {
|
|
||||||
constructor() {
|
|
||||||
this._db = getDB()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Store
|
|
@ -1,43 +0,0 @@
|
|||||||
import Store from './_store.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class State extends Store {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} name
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
add(data) {
|
|
||||||
const result = this.findOneByName(data.name)
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
this._db.prepare('INSERT INTO states (name, date_lastrun) VALUES (:name, :date_lastrun)')
|
|
||||||
.run(data)
|
|
||||||
} else {
|
|
||||||
this._db.prepare('UPDATE states SET name = @name, date_lastrun = @date_lastrun WHERE id = ?')
|
|
||||||
.run(data, result.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.findOneByName(data.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} name
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
findOneByName(name) {
|
|
||||||
const result = this._db.prepare('SELECT id, name, date_lastrun FROM states WHERE name = ?')
|
|
||||||
.get(name)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default State
|
|
@ -0,0 +1,48 @@
|
|||||||
|
import fastify from 'fastify'
|
||||||
|
import dotenv from 'dotenv'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
// getting .env
|
||||||
|
dotenv.config({ path: path.join(path.resolve(), '/../../.env') })
|
||||||
|
|
||||||
|
// create server
|
||||||
|
const server = fastify()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add plugins
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import { Liquid } from 'liquidjs'
|
||||||
|
import pov from 'point-of-view'
|
||||||
|
|
||||||
|
const engine = new Liquid({
|
||||||
|
root: path.join(path.resolve(), '../frontend/views'),
|
||||||
|
extname: '.liquid',
|
||||||
|
})
|
||||||
|
|
||||||
|
server.register(pov, {
|
||||||
|
engine: {
|
||||||
|
liquid: engine
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add routes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import taskHttp from './http/api/task.js'
|
||||||
|
import handlerHttp from './http/api/handler.js'
|
||||||
|
import indexHttp from './http/index.js'
|
||||||
|
import staticHttp from './http/static.js'
|
||||||
|
|
||||||
|
server
|
||||||
|
.register(taskHttp, {
|
||||||
|
'prefix': '/api/v1'
|
||||||
|
})
|
||||||
|
.register(handlerHttp, {
|
||||||
|
'prefix': '/api/v1'
|
||||||
|
})
|
||||||
|
.register(indexHttp)
|
||||||
|
.register(staticHttp)
|
||||||
|
|
||||||
|
export default server
|
@ -0,0 +1,65 @@
|
|||||||
|
import DOMPurify from 'isomorphic-dompurify'
|
||||||
|
import bcrypt from 'bcrypt'
|
||||||
|
|
||||||
|
import UserRepository from './../../repositories/userRepository.js'
|
||||||
|
import loginSchema from './../../schemas/auth/login.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle auth
|
||||||
|
*
|
||||||
|
* @author Björn Hase, Tentakelfabrik
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://github.com/tentakelfabrik/fastify-lowdb-riotjs-lessons-learned
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default async function(fastify, opts)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* auth
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.post('/auth', loginSchema, async function (request, reply)
|
||||||
|
{
|
||||||
|
let { username, password } = request.body
|
||||||
|
|
||||||
|
// strip crap from strings
|
||||||
|
username = DOMPurify.sanitize(username)
|
||||||
|
password = DOMPurify.sanitize(password)
|
||||||
|
|
||||||
|
const userRepository = new UserRepository()
|
||||||
|
const user = await userRepository.findOneByUsername(username)
|
||||||
|
|
||||||
|
// add header for json
|
||||||
|
reply.header('Content-Type', 'application/json; charset=utf-8')
|
||||||
|
|
||||||
|
// user not found
|
||||||
|
if (!user) {
|
||||||
|
return reply
|
||||||
|
.code(404)
|
||||||
|
.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// password wrong
|
||||||
|
if (!bcrypt.compareSync(password, user.password)) {
|
||||||
|
return reply
|
||||||
|
.code(401)
|
||||||
|
.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting session to store and set cookie
|
||||||
|
request.sessionStore.set(request.session.sessionId, request.session, async function() {
|
||||||
|
user.sessionId = request.session.sessionId
|
||||||
|
|
||||||
|
await userRepository.update(user)
|
||||||
|
|
||||||
|
// send 200 and send set-token
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
import * as fs from 'fs'
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getting handlers
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default async function(fastify, opts)
|
||||||
|
{
|
||||||
|
fastify.get('/handler/:namespace(request|action)', async function (request, reply)
|
||||||
|
{
|
||||||
|
// handlers that found
|
||||||
|
const handlers = []
|
||||||
|
|
||||||
|
// directories to find
|
||||||
|
const directories = [
|
||||||
|
'custom',
|
||||||
|
'handlers'
|
||||||
|
]
|
||||||
|
|
||||||
|
// getting
|
||||||
|
directories.forEach((directory) => {
|
||||||
|
|
||||||
|
// create path
|
||||||
|
const directoryPath = './../runner/' + directory + '/' + request.params.namespace
|
||||||
|
|
||||||
|
// adding each from directory
|
||||||
|
fs.readdirSync(directoryPath).forEach(file => {
|
||||||
|
|
||||||
|
let name = file.replace('.js', '')
|
||||||
|
|
||||||
|
// if custom add to name
|
||||||
|
if (request.params.namespace === 'custom') {
|
||||||
|
name += ' (custom)'
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.push({
|
||||||
|
'name': file.replace('.js', ''),
|
||||||
|
'className': file,
|
||||||
|
'file': directoryPath + file
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send({
|
||||||
|
'data': handlers
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
import DOMPurify from 'isomorphic-dompurify'
|
||||||
|
import ActionRepository from './../../repositories/actionRepository.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default async function(fastify, opts)
|
||||||
|
{
|
||||||
|
const actionRepository = new ActionRepository()
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.get('/task', async function (request, reply)
|
||||||
|
{
|
||||||
|
// getting actions
|
||||||
|
const actions = await actionRepository.find({ 'selector': {
|
||||||
|
'type': 'action'
|
||||||
|
}})
|
||||||
|
|
||||||
|
// send 200 and send set-token
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send({
|
||||||
|
'data': actions
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.post('/task', async function (request, reply)
|
||||||
|
{
|
||||||
|
// getting actions
|
||||||
|
const action = await actionRepository.create(request.body)
|
||||||
|
|
||||||
|
// send 200 and send set-token
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send({
|
||||||
|
'data': action
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.put('/task/:id', async function (request, reply)
|
||||||
|
{
|
||||||
|
// getting actions
|
||||||
|
const action = await actionRepository.update({
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// send 200 and send set-token
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send({
|
||||||
|
'data': action
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete single action
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.delete('/task/:id', async function (request, reply)
|
||||||
|
{
|
||||||
|
// getting actions
|
||||||
|
const action = await actionRepository.remove(request.params.id)
|
||||||
|
|
||||||
|
if (!action) {
|
||||||
|
return reply
|
||||||
|
.code(404)
|
||||||
|
.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// send 200 and send set-token
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send({
|
||||||
|
'success': true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
import token from '@fastify/csrf'
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* index
|
||||||
|
*
|
||||||
|
* - home view
|
||||||
|
* - logout user
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default async function(fastify, opts)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* home
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.get('/', (request, response) =>
|
||||||
|
{
|
||||||
|
response.view('../frontend/views/index')
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logout
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.get('/logout', async function(request, response)
|
||||||
|
{
|
||||||
|
request.destroySession(() => {
|
||||||
|
response.redirect('/')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import fastifyStatic from 'fastify-static'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle static
|
||||||
|
*
|
||||||
|
* @author Björn Hase, Tentakelfabrik
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://github.com/tentakelfabrik/fastify-lowdb-riotjs-lessons-learned
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default async function(fastify, opts)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.register(fastifyStatic, {
|
||||||
|
root: path.join(path.resolve(), '/../../public'),
|
||||||
|
prefix: '/',
|
||||||
|
preCompressed: true
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import server from './bootstrap.js'
|
||||||
|
|
||||||
|
// let it rain
|
||||||
|
const start = async () => {
|
||||||
|
try {
|
||||||
|
await server.listen(process.env.APP_PORT)
|
||||||
|
console.log('Server is running on port ' + process.env.APP_PORT)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start()
|
@ -0,0 +1,722 @@
|
|||||||
|
{
|
||||||
|
"name": "server",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@fastify/ajv-compiler": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==",
|
||||||
|
"requires": {
|
||||||
|
"ajv": "^6.12.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@fastify/csrf": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fastify/csrf/-/csrf-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-LkMtGoj0PhnkcbB8W/oWkUKciDY8dnOYEhDUh3h8TmbzhuYd+PtVTMZjM1DcAaSNxLYTjZqe2aX6Rn7tXJO9XA==",
|
||||||
|
"requires": {
|
||||||
|
"rndm": "^1.2.0",
|
||||||
|
"tsscmp": "^1.0.6",
|
||||||
|
"uid-safe": "^2.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"abstract-logging": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
|
||||||
|
},
|
||||||
|
"ajv": {
|
||||||
|
"version": "6.12.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
|
"requires": {
|
||||||
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.4.1",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"archy": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
|
||||||
|
},
|
||||||
|
"atomic-sleep": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="
|
||||||
|
},
|
||||||
|
"avvio": {
|
||||||
|
"version": "7.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.2.tgz",
|
||||||
|
"integrity": "sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw==",
|
||||||
|
"requires": {
|
||||||
|
"archy": "^1.0.0",
|
||||||
|
"debug": "^4.0.0",
|
||||||
|
"fastq": "^1.6.1",
|
||||||
|
"queue-microtask": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"balanced-match": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
|
},
|
||||||
|
"basic-auth": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"brace-expansion": {
|
||||||
|
"version": "1.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
|
"requires": {
|
||||||
|
"balanced-match": "^1.0.0",
|
||||||
|
"concat-map": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"concat-map": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
|
},
|
||||||
|
"content-disposition": {
|
||||||
|
"version": "0.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||||
|
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cookie": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "4.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||||
|
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deepmerge": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
|
||||||
|
},
|
||||||
|
"depd": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||||
|
},
|
||||||
|
"destroy": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||||
|
},
|
||||||
|
"dotenv": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||||
|
},
|
||||||
|
"ee-first": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||||
|
},
|
||||||
|
"encodeurl": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||||
|
},
|
||||||
|
"encoding-negotiator": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/encoding-negotiator/-/encoding-negotiator-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-GSK7qphNR4iPcejfAlZxKDoz3xMhnspwImK+Af5WhePS9jUpK/Oh7rUdyENWu+9rgDflOCTmAojBsgsvM8neAQ=="
|
||||||
|
},
|
||||||
|
"escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||||
|
},
|
||||||
|
"etag": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
|
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
|
||||||
|
},
|
||||||
|
"fast-decode-uri-component": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
|
||||||
|
},
|
||||||
|
"fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
|
},
|
||||||
|
"fast-json-stable-stringify": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||||
|
},
|
||||||
|
"fast-json-stringify": {
|
||||||
|
"version": "2.7.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz",
|
||||||
|
"integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==",
|
||||||
|
"requires": {
|
||||||
|
"ajv": "^6.11.0",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"rfdc": "^1.2.0",
|
||||||
|
"string-similarity": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fast-redact": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-dir8LOnvialLxiXDPESMDHGp82CHi6ZEYTVkcvdn5d7psdv9ZkkButXrOeXST4aqreIRR+N7CYlsrwFuorurVg=="
|
||||||
|
},
|
||||||
|
"fast-safe-stringify": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
||||||
|
},
|
||||||
|
"fastify": {
|
||||||
|
"version": "3.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify/-/fastify-3.27.0.tgz",
|
||||||
|
"integrity": "sha512-p99Fd7xt4DFew39U5Wnp/Soy7jkpxpaqToekwQ3XWv+ECUPXd6bSF9l79EiwkutWALtEU/JiRlzS9qjP2gLHFg==",
|
||||||
|
"requires": {
|
||||||
|
"@fastify/ajv-compiler": "^1.0.0",
|
||||||
|
"abstract-logging": "^2.0.0",
|
||||||
|
"avvio": "^7.1.2",
|
||||||
|
"fast-json-stringify": "^2.5.2",
|
||||||
|
"fastify-error": "^0.3.0",
|
||||||
|
"find-my-way": "^4.5.0",
|
||||||
|
"flatstr": "^1.0.12",
|
||||||
|
"light-my-request": "^4.2.0",
|
||||||
|
"pino": "^6.13.0",
|
||||||
|
"process-warning": "^1.0.0",
|
||||||
|
"proxy-addr": "^2.0.7",
|
||||||
|
"rfdc": "^1.1.4",
|
||||||
|
"secure-json-parse": "^2.0.0",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"tiny-lru": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fastify-auth": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-auth/-/fastify-auth-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-8IajmAZB3QJ3wTP0q8Z3TG9DkxrIcAlS85TdPCBEfJi3mMKQd/sCYxtZ0dYv11v5hZaJ9z8XmNzhK3AH6/JpNw==",
|
||||||
|
"requires": {
|
||||||
|
"fastify-plugin": "^3.0.0",
|
||||||
|
"reusify": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fastify-basic-auth": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-basic-auth/-/fastify-basic-auth-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-xXeNhyhONlQNoWIzy9rhms0td6PFL1KCRqu0lkEpd54Ju4dHLbB/woPwtK0Vutuqy0sDav77If6UtdfDajx44Q==",
|
||||||
|
"requires": {
|
||||||
|
"basic-auth": "^2.0.1",
|
||||||
|
"fastify-plugin": "^3.0.0",
|
||||||
|
"http-errors": "^1.7.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fastify-error": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ=="
|
||||||
|
},
|
||||||
|
"fastify-formbody": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-formbody/-/fastify-formbody-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-d8Y5hCL82akPyoFiXh2wYOm3es0pV9jqoPo3pO9OV2cNF0cQx39J5WAVXzCh4MSt9Z2qF4Fy5gHlvlyESwjtvg==",
|
||||||
|
"requires": {
|
||||||
|
"fastify-plugin": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fastify-plugin": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w=="
|
||||||
|
},
|
||||||
|
"fastify-static": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-static/-/fastify-static-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-Q7Tgl55AjsmBwiO4hKYib2BUCt+XTWLJ6Xp8YPPHU3EsrKNpevJ4cz8pjf1Ey1QhHw9O8Y2FDKdu+IC74oHvqw==",
|
||||||
|
"requires": {
|
||||||
|
"content-disposition": "^0.5.3",
|
||||||
|
"encoding-negotiator": "^2.0.1",
|
||||||
|
"fastify-plugin": "^3.0.0",
|
||||||
|
"glob": "^7.1.4",
|
||||||
|
"p-limit": "^3.1.0",
|
||||||
|
"readable-stream": "^3.4.0",
|
||||||
|
"send": "^0.17.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fastify-warning": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
|
||||||
|
},
|
||||||
|
"fastq": {
|
||||||
|
"version": "1.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
|
||||||
|
"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
|
||||||
|
"requires": {
|
||||||
|
"reusify": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"find-my-way": {
|
||||||
|
"version": "4.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.5.1.tgz",
|
||||||
|
"integrity": "sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==",
|
||||||
|
"requires": {
|
||||||
|
"fast-decode-uri-component": "^1.0.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"safe-regex2": "^2.0.0",
|
||||||
|
"semver-store": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flatstr": {
|
||||||
|
"version": "1.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
|
||||||
|
"integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
|
||||||
|
},
|
||||||
|
"forwarded": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
|
||||||
|
},
|
||||||
|
"fresh": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
|
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||||
|
},
|
||||||
|
"fs.realpath": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
|
},
|
||||||
|
"glob": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||||
|
"requires": {
|
||||||
|
"fs.realpath": "^1.0.0",
|
||||||
|
"inflight": "^1.0.4",
|
||||||
|
"inherits": "2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"path-is-absolute": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hashlru": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A=="
|
||||||
|
},
|
||||||
|
"http-errors": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
|
||||||
|
"requires": {
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"inherits": "2.0.4",
|
||||||
|
"setprototypeof": "1.2.0",
|
||||||
|
"statuses": ">= 1.5.0 < 2",
|
||||||
|
"toidentifier": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inflight": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
|
"requires": {
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
|
},
|
||||||
|
"ipaddr.js": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||||
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||||
|
},
|
||||||
|
"light-my-request": {
|
||||||
|
"version": "4.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.7.0.tgz",
|
||||||
|
"integrity": "sha512-LTa8YZp3K2AUpqUnwwKajoIHcsKOBnzwJNQSrk7unziPwo6CjOYjyO0F9wfkxFvP+nBsCGe3eMPnedVgIIgdAw==",
|
||||||
|
"requires": {
|
||||||
|
"ajv": "^8.1.0",
|
||||||
|
"cookie": "^0.4.0",
|
||||||
|
"fastify-warning": "^0.2.0",
|
||||||
|
"set-cookie-parser": "^2.4.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": {
|
||||||
|
"version": "8.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz",
|
||||||
|
"integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==",
|
||||||
|
"requires": {
|
||||||
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"liquidjs": {
|
||||||
|
"version": "9.33.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-9.33.1.tgz",
|
||||||
|
"integrity": "sha512-qIMSXkUMFG5VZmBp1qxcOEFeGzmA2A8Fy818rMTAWKyy2ftUwOEoVtvXFdqm3iSeQEoj8pzTOmC6KQOP0SipUA=="
|
||||||
|
},
|
||||||
|
"lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"requires": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mime": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||||
|
},
|
||||||
|
"minimatch": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
|
"requires": {
|
||||||
|
"brace-expansion": "^1.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
|
"on-finished": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||||
|
"requires": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
|
"requires": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-limit": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||||
|
"requires": {
|
||||||
|
"yocto-queue": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"path-is-absolute": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||||
|
},
|
||||||
|
"pino": {
|
||||||
|
"version": "6.13.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pino/-/pino-6.13.4.tgz",
|
||||||
|
"integrity": "sha512-g4tHSISmQJYUEKEMVdaZ+ZokWwFnTwZL5JPn+lnBVZ1BuBbrSchrXwQINknkM5+Q4fF6U9NjiI8PWwwMDHt9zA==",
|
||||||
|
"requires": {
|
||||||
|
"fast-redact": "^3.0.0",
|
||||||
|
"fast-safe-stringify": "^2.0.8",
|
||||||
|
"flatstr": "^1.0.12",
|
||||||
|
"pino-std-serializers": "^3.1.0",
|
||||||
|
"process-warning": "^1.0.0",
|
||||||
|
"quick-format-unescaped": "^4.0.3",
|
||||||
|
"sonic-boom": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pino-std-serializers": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg=="
|
||||||
|
},
|
||||||
|
"point-of-view": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/point-of-view/-/point-of-view-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-JY12G3+jVFYccKTexe2OHG9WHrEUb3eLKPtLM/YEnaJf2i2OuzIun/v6SBzjHFm5sOuNXyKKo47HIe/YkGtEMA==",
|
||||||
|
"requires": {
|
||||||
|
"fastify-plugin": "^3.0.0",
|
||||||
|
"hashlru": "^2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"process-warning": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="
|
||||||
|
},
|
||||||
|
"proxy-addr": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||||
|
"requires": {
|
||||||
|
"forwarded": "0.2.0",
|
||||||
|
"ipaddr.js": "1.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"punycode": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
|
},
|
||||||
|
"queue-microtask": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
|
||||||
|
},
|
||||||
|
"quick-format-unescaped": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
|
||||||
|
},
|
||||||
|
"random-bytes": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
|
||||||
|
},
|
||||||
|
"range-parser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||||
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require-from-string": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
|
||||||
|
},
|
||||||
|
"ret": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ=="
|
||||||
|
},
|
||||||
|
"reusify": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
|
||||||
|
},
|
||||||
|
"rfdc": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
|
||||||
|
},
|
||||||
|
"rndm": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w="
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||||
|
},
|
||||||
|
"safe-regex2": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==",
|
||||||
|
"requires": {
|
||||||
|
"ret": "~0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"secure-json-parse": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg=="
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "7.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||||
|
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||||
|
"requires": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"semver-store": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg=="
|
||||||
|
},
|
||||||
|
"send": {
|
||||||
|
"version": "0.17.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
|
||||||
|
"integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"destroy": "~1.0.4",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"http-errors": "1.8.1",
|
||||||
|
"mime": "1.6.0",
|
||||||
|
"ms": "2.1.3",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"range-parser": "~1.2.1",
|
||||||
|
"statuses": "~1.5.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"set-cookie-parser": {
|
||||||
|
"version": "2.4.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz",
|
||||||
|
"integrity": "sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg=="
|
||||||
|
},
|
||||||
|
"setprototypeof": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
||||||
|
},
|
||||||
|
"sonic-boom": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==",
|
||||||
|
"requires": {
|
||||||
|
"atomic-sleep": "^1.0.0",
|
||||||
|
"flatstr": "^1.0.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statuses": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||||
|
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
||||||
|
},
|
||||||
|
"string-similarity": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ=="
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tiny-lru": {
|
||||||
|
"version": "7.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz",
|
||||||
|
"integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow=="
|
||||||
|
},
|
||||||
|
"toidentifier": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
|
||||||
|
},
|
||||||
|
"tsscmp": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="
|
||||||
|
},
|
||||||
|
"uid-safe": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
||||||
|
"requires": {
|
||||||
|
"random-bytes": "~1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uri-js": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||||
|
"requires": {
|
||||||
|
"punycode": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
|
},
|
||||||
|
"wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
|
},
|
||||||
|
"yocto-queue": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "server",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@fastify/csrf": "^4.0.1",
|
||||||
|
"dotenv": "^10.0.0",
|
||||||
|
"fastify": "^3.27.0",
|
||||||
|
"fastify-auth": "^1.1.0",
|
||||||
|
"fastify-basic-auth": "^2.2.0",
|
||||||
|
"fastify-formbody": "^5.2.0",
|
||||||
|
"fastify-static": "^4.5.0",
|
||||||
|
"liquidjs": "^9.33.1",
|
||||||
|
"point-of-view": "^5.0.0",
|
||||||
|
"pouchdb": "^7.2.2",
|
||||||
|
"pouchdb-find": "^7.2.2"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
import { Liquid } from 'liquidjs'
|
||||||
|
import pov from 'point-of-view'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plugin: usindg render engine liquidjs
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function plugin(fastify, options)
|
||||||
|
{
|
||||||
|
const engine = new Liquid({
|
||||||
|
root: path.join(path.resolve(), '/../../frontend/views'),
|
||||||
|
extname: '.liquid',
|
||||||
|
})
|
||||||
|
|
||||||
|
fastify.register(pov, {
|
||||||
|
engine: {
|
||||||
|
liquid: engine
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default plugin
|
@ -0,0 +1,212 @@
|
|||||||
|
import fastifySession from '@fastify/session'
|
||||||
|
import fastifyCookie from 'fastify-cookie'
|
||||||
|
|
||||||
|
import PouchDB from 'pouchdb'
|
||||||
|
import PouchDBfind from 'pouchdb-find'
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pouchdb storage
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @extends Store
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PouchdbStore extends Store
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {Object}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super()
|
||||||
|
|
||||||
|
PouchDB.plugin(PouchDBfind)
|
||||||
|
|
||||||
|
// create db if not already exists
|
||||||
|
this.db = new PouchDB('./../../storage/session', {
|
||||||
|
revs_limit: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} sessionId [description]
|
||||||
|
* @param {Function} callback [description]
|
||||||
|
*/
|
||||||
|
async set(sessionId, session, callback)
|
||||||
|
{
|
||||||
|
const result = await this.db.find({
|
||||||
|
'selector': {
|
||||||
|
'_id': sessionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.docs.length === 0) {
|
||||||
|
session._id = sessionId
|
||||||
|
await this.db.post(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} sessionId [description]
|
||||||
|
* @param {Function} callback [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
async get(sessionId, callback)
|
||||||
|
{
|
||||||
|
const result = await this.db.find({
|
||||||
|
'selector': {
|
||||||
|
'_id': sessionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let session = null
|
||||||
|
|
||||||
|
if (result.docs.length > 0) {
|
||||||
|
session = result.docs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} sessionId [description]
|
||||||
|
* @param {Function} callback [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
async destroy(sessionId, callback)
|
||||||
|
{
|
||||||
|
const result = await this.db.find({
|
||||||
|
'selector': {
|
||||||
|
'_id': sessionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.docs.length > 0) {
|
||||||
|
await this.db.remove(result.docs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const loginSchema = {
|
||||||
|
schema: {
|
||||||
|
body: {
|
||||||
|
username: { type: 'string' },
|
||||||
|
password: { type: 'string' }
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
200: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
token: { type: 'string' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create Plugin
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function plugin(fastify, options, next) {
|
||||||
|
{
|
||||||
|
// create cookie
|
||||||
|
fastify
|
||||||
|
.register(fastifyCookie)
|
||||||
|
.register(fastifySession, {
|
||||||
|
secret: options.secret,
|
||||||
|
cookieName: 'session',
|
||||||
|
cookie: {
|
||||||
|
path: '/',
|
||||||
|
maxAge: options.secret,
|
||||||
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: 'Strict'
|
||||||
|
},
|
||||||
|
store: new PouchdbStore()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* route: logout user and destroy session
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.get('/logout', async function(request, response)
|
||||||
|
{
|
||||||
|
request.destroySession(() => {
|
||||||
|
response.redirect('/')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* route: auth
|
||||||
|
*
|
||||||
|
* @param {object} request
|
||||||
|
* @param {object} response
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fastify.post('/auth', loginSchema, async function (request, reply)
|
||||||
|
{
|
||||||
|
let { username, password } = request.body
|
||||||
|
|
||||||
|
// strip crap from strings
|
||||||
|
username = DOMPurify.sanitize(username)
|
||||||
|
password = DOMPurify.sanitize(password)
|
||||||
|
|
||||||
|
const userRepository = new UserRepository()
|
||||||
|
const user = await userRepository.findOneByUsername(username)
|
||||||
|
|
||||||
|
// add header for json
|
||||||
|
reply.header('Content-Type', 'application/json; charset=utf-8')
|
||||||
|
|
||||||
|
// user not found
|
||||||
|
if (!user) {
|
||||||
|
return reply
|
||||||
|
.code(404)
|
||||||
|
.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// password wrong
|
||||||
|
if (!bcrypt.compareSync(password, user.password)) {
|
||||||
|
return reply
|
||||||
|
.code(401)
|
||||||
|
.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting session to store and set cookie
|
||||||
|
request.sessionStore.set(request.session.sessionId, request.session, async function() {
|
||||||
|
user.sessionId = request.session.sessionId
|
||||||
|
|
||||||
|
await userRepository.update(user)
|
||||||
|
|
||||||
|
// send 200 and send set-token
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.send()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = plugin
|
@ -0,0 +1,23 @@
|
|||||||
|
import Repository from './repository.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ActionRepository extends Repository
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.type = 'action'
|
||||||
|
this.index.push('name')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ActionRepository
|
@ -0,0 +1,174 @@
|
|||||||
|
import PouchDB from 'pouchdb'
|
||||||
|
import PouchDBfind from 'pouchdb-find'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Repository
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
PouchDB.plugin(PouchDBfind)
|
||||||
|
this.db = new PouchDB('./../../storage/database', {
|
||||||
|
revs_limit: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// adding index
|
||||||
|
this.index = [
|
||||||
|
'type'
|
||||||
|
]
|
||||||
|
|
||||||
|
if (this.index && this.index.lenth > 0) {
|
||||||
|
this.addIndex(this.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add index
|
||||||
|
*
|
||||||
|
* @param {array} fields
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async addIndex(fields)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
await this.db.createIndex({
|
||||||
|
index: {
|
||||||
|
fields: fields
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {array} data
|
||||||
|
* @param {function} success
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
create(data)
|
||||||
|
{
|
||||||
|
//data._id = uuidv4()
|
||||||
|
data.type = this.type
|
||||||
|
|
||||||
|
// if beforeCreate exists
|
||||||
|
if (typeof this['beforeCreate'] === 'function') {
|
||||||
|
data = this.beforeCreate(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.db.post(data)
|
||||||
|
.then((response) => {
|
||||||
|
|
||||||
|
console.log(response)
|
||||||
|
|
||||||
|
// if afterCreate exists
|
||||||
|
if (typeof this['afterCreate'] === 'function') {
|
||||||
|
this.afterCreate(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {array} data
|
||||||
|
* @param {function} success
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
update(data)
|
||||||
|
{
|
||||||
|
// if beforeUpdate exists
|
||||||
|
if (typeof this['beforeUpdate'] === 'function') {
|
||||||
|
data = this.beforeUpdate(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.db.put(data)
|
||||||
|
.then((response) => {
|
||||||
|
|
||||||
|
// if beforeUpdate exists
|
||||||
|
if (typeof this['afterUpdate'] === 'function') {
|
||||||
|
this.afterUpdate(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {string} id
|
||||||
|
* @param {function} success
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async remove(id)
|
||||||
|
{
|
||||||
|
this.findOne({
|
||||||
|
'selector': {
|
||||||
|
'_id': id
|
||||||
|
}
|
||||||
|
}).then((document) => {
|
||||||
|
if (document) {
|
||||||
|
|
||||||
|
// if beforeUpdate exists
|
||||||
|
if (typeof this['beforeRemove'] === 'function') {
|
||||||
|
this.beforeRemove(document)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.db.remove(document._id, document._rev, () => {
|
||||||
|
return document
|
||||||
|
})
|
||||||
|
|
||||||
|
// if beforeUpdate exists
|
||||||
|
if (typeof this['afterRemove'] === 'function') {
|
||||||
|
this.afterRemove(document)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find documents
|
||||||
|
*
|
||||||
|
* @param {object} fields
|
||||||
|
* @param {object} query
|
||||||
|
* @param {function} success
|
||||||
|
*/
|
||||||
|
find(query)
|
||||||
|
{
|
||||||
|
return this.db.find(query).then((documents) => {
|
||||||
|
return documents.docs
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find documents
|
||||||
|
*
|
||||||
|
* @param {object} fields
|
||||||
|
* @param {object} query
|
||||||
|
* @param {function} success
|
||||||
|
*/
|
||||||
|
findOne(query)
|
||||||
|
{
|
||||||
|
return this.db.find(query).then((documents) => {
|
||||||
|
if (documents.docs.length === 0) {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
return documents.docs[0]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Repository
|
@ -0,0 +1,70 @@
|
|||||||
|
import Repository from './repository.js'
|
||||||
|
import bcrypt from 'bcrypt'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Björn Hase, me@herr-hase.wtf
|
||||||
|
* @license http://opensource.org/licenses/MIT The MIT License
|
||||||
|
* @link https://gitea.node001.net/HerrHase/super-hog
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UserRepository extends Repository
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super()
|
||||||
|
this.type = 'user'
|
||||||
|
|
||||||
|
this.index.push('username')
|
||||||
|
this.index.push('sessionId')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[type]} data
|
||||||
|
* @return {[type]}
|
||||||
|
*/
|
||||||
|
beforeCreate(data)
|
||||||
|
{
|
||||||
|
if (data.password) {
|
||||||
|
const salt = bcrypt.genSaltSync(15)
|
||||||
|
data.password = bcrypt.hashSync(data.password, salt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getting user by username
|
||||||
|
*
|
||||||
|
* @param {string} username
|
||||||
|
* @return {promise}
|
||||||
|
*/
|
||||||
|
async findOneByUsername(username)
|
||||||
|
{
|
||||||
|
return this.findOne({
|
||||||
|
'selector': {
|
||||||
|
'username': username
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getting user by sessionToken
|
||||||
|
*
|
||||||
|
* @param {string} sessionToken
|
||||||
|
* @return {promise}
|
||||||
|
*/
|
||||||
|
findOneBySessionId(sessionId)
|
||||||
|
{
|
||||||
|
return this.findOne({
|
||||||
|
'selector': {
|
||||||
|
'sessionId': sessionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserRepository
|
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
schema: {
|
||||||
|
body: {
|
||||||
|
username: { type: 'string' },
|
||||||
|
password: { type: 'string' }
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
200: {
|
||||||
|
type: 'object'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,93 @@
|
|||||||
|
Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
@ -0,0 +1,233 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="robots" content="noindex, noarchive">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<title>Transfonter demo</title>
|
||||||
|
<link href="stylesheet.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
/*
|
||||||
|
http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
/* demo styles */
|
||||||
|
body {
|
||||||
|
background: #f0f0f0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
background: #fff;
|
||||||
|
width: 920px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.font-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
line-height: 1.3;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
position: relative;
|
||||||
|
background: #444;
|
||||||
|
font-size: 32px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 -20px 12px -20px;
|
||||||
|
}
|
||||||
|
.letters {
|
||||||
|
font-size: 25px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.s10:before {
|
||||||
|
content: '10px';
|
||||||
|
}
|
||||||
|
.s11:before {
|
||||||
|
content: '11px';
|
||||||
|
}
|
||||||
|
.s12:before {
|
||||||
|
content: '12px';
|
||||||
|
}
|
||||||
|
.s14:before {
|
||||||
|
content: '14px';
|
||||||
|
}
|
||||||
|
.s18:before {
|
||||||
|
content: '18px';
|
||||||
|
}
|
||||||
|
.s24:before {
|
||||||
|
content: '24px';
|
||||||
|
}
|
||||||
|
.s30:before {
|
||||||
|
content: '30px';
|
||||||
|
}
|
||||||
|
.s36:before {
|
||||||
|
content: '36px';
|
||||||
|
}
|
||||||
|
.s48:before {
|
||||||
|
content: '48px';
|
||||||
|
}
|
||||||
|
.s60:before {
|
||||||
|
content: '60px';
|
||||||
|
}
|
||||||
|
.s72:before {
|
||||||
|
content: '72px';
|
||||||
|
}
|
||||||
|
.s10:before, .s11:before, .s12:before, .s14:before,
|
||||||
|
.s18:before, .s24:before, .s30:before, .s36:before,
|
||||||
|
.s48:before, .s60:before, .s72:before {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
color: #999;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding: 9px;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.428571429;
|
||||||
|
color: #333;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
pre:after {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
content: 'Usage';
|
||||||
|
line-height: 1;
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #767676;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-right: none;
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 4px 0 4px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
/* responsive */
|
||||||
|
@media (max-width: 959px) {
|
||||||
|
.page {
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="page">
|
||||||
|
<div class="demo">
|
||||||
|
<h1 style="font-family: 'IBM Plex Mono'; font-weight: normal; font-style: normal;">IBM Plex Mono</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'IBM Plex Mono';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container" style="font-family: 'IBM Plex Mono'; font-weight: normal; font-style: normal;">
|
||||||
|
<p class="letters">
|
||||||
|
abcdefghijklmnopqrstuvwxyz<br>
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||||
|
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo">
|
||||||
|
<h1 style="font-family: 'IBM Plex Mono'; font-weight: bold; font-style: normal;">IBM Plex Mono Bold</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'IBM Plex Mono';
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container" style="font-family: 'IBM Plex Mono'; font-weight: bold; font-style: normal;">
|
||||||
|
<p class="letters">
|
||||||
|
abcdefghijklmnopqrstuvwxyz<br>
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||||
|
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'IBM Plex Mono';
|
||||||
|
src: url('IBMPlexMono.eot');
|
||||||
|
src: url('IBMPlexMono.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('IBMPlexMono.woff2') format('woff2'),
|
||||||
|
url('IBMPlexMono.woff') format('woff'),
|
||||||
|
url('IBMPlexMono.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'IBM Plex Mono';
|
||||||
|
src: url('IBMPlexMono-Bold.eot');
|
||||||
|
src: url('IBMPlexMono-Bold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('IBMPlexMono-Bold.woff2') format('woff2'),
|
||||||
|
url('IBMPlexMono-Bold.woff') format('woff'),
|
||||||
|
url('IBMPlexMono-Bold.ttf') format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
|||||||
|
(self["webpackChunkfrontend"] = self["webpackChunkfrontend"] || []).push([["spritemap"],{
|
||||||
|
|
||||||
|
/***/ "?c20d":
|
||||||
|
/*!******************************!*\
|
||||||
|
!*** spritemap-dummy-module ***!
|
||||||
|
\******************************/
|
||||||
|
/***/ (() => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
}]);
|
After Width: | Height: | Size: 66 KiB |
Loading…
Reference in new issue