feat: Add Authentication Support and Start of Frontend (#5)

* Setup Authentication On Resources

* Go mod tidy

* git ignore node modules

* Frontend Template

* Work on setting up vue frontend

* Github Actions

* More work on Auth and Frontend.

* update dependabot

* add Reviewers

* Fix Up Labels

* Update CodeQL Tests

* Fix Format

* Fix Formating

* More Updates to github actions and bundled frontend files

* Fix Formating

* increase timeout

* Password Checking/Setting Functions
This commit is contained in:
Justin Hammond 2022-08-16 13:42:18 +08:00 committed by GitHub
parent 77d898cb4a
commit ccf6d3ed3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
172 changed files with 39212 additions and 198 deletions

View file

@ -10,4 +10,20 @@ updates:
schedule:
interval: "daily"
labels:
- "type: dependencies"
- "dependencies"
- "backend"
reviewers:
- "fishwaldo"
commit-message:
prefix: "chore"
- package-ecosystem: "npm"
directory: "/frontend/"
schedule:
interval: "daily"
labels:
- "dependencies"
- "frontend"
reviewers:
- "fishwaldo"
commit-message:
prefix: "chore"

18
.github/labeler.yml vendored
View file

@ -1,21 +1,21 @@
version: v1
labels:
- label: "type: feature"
- label: "feature"
sync: true
matcher:
title: "^feat: .*"
commits: "^feat: .*"
body: "(\\n|.)*- \\[x\\] feature(\\n|.)*"
- label: "type: fix"
- label: "fix"
sync: true
matcher:
title: "^fix: .*"
commits: "^fix: .*"
body: "(\\n|.)*- \\[x\\] (fix|bug)(\\n|.)*"
- label: "type: chore"
- label: "chore"
sync: true
matcher:
title: "^chore: .*"
@ -23,7 +23,7 @@ labels:
body: "(\\n|.)*- \\[x\\] chore(\\n|.)*"
files: [ ".github/*" ]
- label: "type: documentation"
- label: "documentation"
sync: true
matcher:
title: "^docs: .*"
@ -38,8 +38,8 @@ checks:
failure: Missing semantic label for merge.
labels:
any:
- 'type: feature'
- 'type: fix'
- 'type: chore'
- 'type: documentation'
- 'type: dependencies'
- 'feature'
- 'fix'
- 'chore'
- 'documentation'
- 'dependencies'

View file

@ -16,8 +16,17 @@ jobs:
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
- name: Install NPM
if: success()
uses: actions/setup-node@v3
with:
node-version: 16
- name: Checkout code
uses: actions/checkout@v1
- name: install Node Dependancies
run: cd frontend && npm install
- name: Build Frontend
run: cd frontend && npm run build
- name: Build
run: go build .
- name: Run tests
@ -34,6 +43,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install NPM
if: success()
uses: actions/setup-node@v3
with:
node-version: 16
- name: Build Frontend
run: cd frontend && npm install && npm run build
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
@ -47,14 +63,21 @@ jobs:
runs-on: ubuntu-latest
needs: [ test ]
steps:
- name: Install Go
if: success()
uses: actions/setup-go@v1
with:
go-version: 1.18.x
- name: Checkout code
uses: actions/checkout@v1
- name: Run tests
run: go mod tidy && go test -v -race -covermode=atomic -coverprofile=coverage.out ./...
- name: CodeCov
uses: codecov/codecov-action@v2
- name: Install Go
if: success()
uses: actions/setup-go@v1
with:
go-version: 1.18.x
- name: Checkout code
uses: actions/checkout@v1
- name: Install NPM
if: success()
uses: actions/setup-node@v3
with:
node-version: 16
- name: Build Frontend
run: cd frontend && npm install && npm run build
- name: Run tests
run: go mod tidy && go test -v -race -covermode=atomic -coverprofile=coverage.out ./...
- name: CodeCov
uses: codecov/codecov-action@v2

View file

@ -29,7 +29,7 @@ jobs:
# working-directory: somedir
# Optional: golangci-lint command line arguments.
args: --issues-exit-code=0
args: --issues-exit-code=0 --timeout=5m
# Optional: show only new issues if it's a pull request. The default value is `false`.
only-new-issues: true

41
.github/workflows/goreleaser.yml vendored Normal file
View file

@ -0,0 +1,41 @@
name: goreleaser
on:
push:
# run only against tags
tags:
- '*'
permissions:
contents: write
# packages: write
# issues: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Fetch all tags
run: git fetch --force --tags
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.18
- name: Install NPM
if: success()
uses: actions/setup-node@v3
with:
node-version: 16
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6
.gitignore vendored
View file

@ -16,3 +16,9 @@
config.yaml
.gitignore
.gitignore
mouthpiece
test.db
frontend/node_modules/
frontend/dist/
dist/
test.db-journal

40
.goreleaser.yaml Normal file
View file

@ -0,0 +1,40 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# Build html frontend
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
flags:
- -trimpath
ldflags:
- -s -w -X github.com/Fishwaldo/mouthpiece/internal.gitVersion={{.Version}} -X github.com/Fishwaldo/mouthpiece/internal.gitCommit={{.ShortCommit}} -X github.com/Fishwaldo/mouthpiece/internal.buildDate={{.Date}}
asmflags:
#- all=-trimpath
gcflags:
#- all=-trimpath
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'

16
config/auth_model.conf Normal file
View file

@ -0,0 +1,16 @@
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
g2 = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act

3
frontend/.browserslistrc Normal file
View file

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

14
frontend/.editorconfig Normal file
View file

@ -0,0 +1,14 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

3
frontend/.eslintignore Normal file
View file

@ -0,0 +1,3 @@
node_modules/*
/dist/**
.eslintrc.js

43
frontend/.eslintrc.js Normal file
View file

@ -0,0 +1,43 @@
module.exports = {
root: true,
env: {
node: true,
},
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'plugin:prettier/recommended',
],
parserOptions: {
parser: '@typescript-eslint/parser',
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 'off',
'prettier/prettier': 'off',
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)',
],
env: {
jest: true,
},
},
],
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'plugin:prettier/recommended',
'@vue/typescript'
]
}

7
frontend/.prettierrc.js Normal file
View file

@ -0,0 +1,7 @@
module.exports = {
// jsxBracketSameLine: true,
semi: false,
trailingComma: "all",
singleQuote: true,
tabWidth: 2
};

195
frontend/README.md Normal file
View file

@ -0,0 +1,195 @@
[![@coreui coreui](https://img.shields.io/badge/@coreui%20-coreui-lightgrey.svg?style=flat-square)](https://github.com/coreui/coreui)
[![npm package][npm-coreui-badge]][npm-coreui]
[![NPM downloads][npm-coreui-download]][npm-coreui]
[![@coreui vue](https://img.shields.io/badge/@coreui%20-vue-lightgrey.svg?style=flat-square)](https://github.com/coreui/vue)
[![npm package][npm-coreui-vue-badge]][npm-coreui-vue]
[![NPM downloads][npm-coreui-vue-download]][npm-coreui-vue]
[![npm next][npm-next]][npm]
[npm-coreui]: https://www.npmjs.com/package/@coreui/coreui
[npm-coreui-badge]: https://img.shields.io/npm/v/@coreui/coreui.png?style=flat-square
[npm-coreui-download]: https://img.shields.io/npm/dm/@coreui/coreui.svg?style=flat-square
[npm-coreui-vue]: https://www.npmjs.com/package/@coreui/vue
[npm-coreui-vue-badge]: https://img.shields.io/npm/v/@coreui/vue.png?style=flat-square
[npm-coreui-vue-download]: https://img.shields.io/npm/dm/@coreui/vue.svg?style=flat-square
[npm-next]: https://img.shields.io/npm/v/@coreui/vue/next.png?style=flat-square
[npm]: https://www.npmjs.com/package/@coreui/vue
# CoreUI Free Vue Admin Template v4
CoreUI is meant to be the UX game changer. Pure & transparent code is devoid of redundant components, so the app is light enough to offer ultimate user experience. This means mobile devices also, where the navigation is just as easy and intuitive as on a desktop or laptop. The CoreUI Layout API lets you customize your project for almost any device be it Mobile, Web or WebApp CoreUI covers them all!
## Table of Contents
* [Versions](#versions)
* [CoreUI Pro](#coreui-pro)
* [Quick Start](#quick-start)
* [Installation](#installation)
* [Basic usage](#basic-usage)
* [What's included](#whats-included)
* [Documentation](#documentation)
* [Versioning](#versioning)
* [Creators](#creators)
* [Community](#community)
* [Copyright and License](#copyright-and-license)
## Versions
* [CoreUI Free Bootstrap Admin Template](https://github.com/coreui/coreui-free-bootstrap-admin-template)
* [CoreUI Free Angular Admin Template](https://github.com/coreui/coreui-free-angular-admin-template)
* [CoreUI Free React.js Admin Template](https://github.com/coreui/coreui-free-react-admin-template)
* [CoreUI Free Vue.js Admin Template](https://github.com/coreui/coreui-free-vue-admin-template)
## CoreUI Pro
* 💪 [CoreUI Pro Angular Admin Template](https://coreui.io/product/angular-dashboard-template/)
* 💪 [CoreUI Pro Bootstrap Admin Template](https://coreui.io/product/bootstrap-dashboard-template/)
* 💪 [CoreUI Pro React Admin Template](https://coreui.io/product/react-dashboard-template/)
* 💪 [CoreUI Pro Vue Admin Template](https://coreui.io/product/vue-dashboard-template/)
## Quick Start
- [Download the latest release](https://github.com/coreui/coreui-free-vue-admin-template/archive/refs/heads/main.zip)
- Clone the repo: `git clone https://github.com/coreui/coreui-free-vue-admin-template.git`
### Instalation
``` bash
$ npm install
```
or
``` bash
$ yarn install
```
### Basic usage
``` bash
# dev server with hot reload at http://localhost:3000
$ npm run serve
```
or
``` bash
# dev server with hot reload at http://localhost:3000
$ yarn serve
```
Navigate to [http://localhost:3000](http://localhost:3000). The app will automatically reload if you change any of the source files.
#### Build
Run `build` to build the project. The build artifacts will be stored in the `build/` directory.
```bash
# build for production with minification
$ npm run build
```
or
```bash
# build for production with minification
$ yarn build
```
## What's included
Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this:
```
coreui-free-vue-admin-template
├── public/ # static files
│ └── index.html # html template
├── src/ # project root
│ ├── assets/ # images, icons, etc.
│ ├── components/ # common components - header, footer, sidebar, etc.
│ ├── layouts/ # layout containers
│ ├── scss/ # scss styles
│ ├── router # routes config
│ └── store # template state example
│ ├── views/ # application views
│ ├── _nav.js # sidebar navigation config
│ ├── App.vue
│ ├── ...
│ └── main.js
└── package.json
```
## Documentation
The documentation for the CoreUI Admin Template is hosted at our website [CoreUI for Vue](https://coreui.io/vue/)
## Versioning
For transparency into our release cycle and in striving to maintain backward compatibility, CoreUI Free Admin Template is maintained under [the Semantic Versioning guidelines](http://semver.org/).
See [the Releases section of our project](https://github.com/coreui/coreui-free-vue-admin-template/releases) for changelogs for each release version.
## Creators
**Łukasz Holeczek**
* <https://twitter.com/lukaszholeczek>
* <https://github.com/mrholek>
* <https://github.com/coreui>
**CoreUI team**
* https://github.com/orgs/coreui/people
## Community
Get updates on CoreUI's development and chat with the project maintainers and community members.
- Follow [@core_ui on Twitter](https://twitter.com/core_ui).
- Read and subscribe to [CoreUI Blog](https://coreui.io/blog/).
## Support CoreUI Development
CoreUI is an MIT-licensed open source project and is completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing. You can support development by buying the [CoreUI PRO](https://coreui.io/pricing/) or by becoming a sponsor via [Open Collective](https://opencollective.com/coreui/).
<!--- StartOpenCollectiveBackers -->
### Platinum Sponsors
Support this project by [becoming a Platinum Sponsor](https://opencollective.com/coreui/contribute/platinum-sponsor-40959/). A large company logo will be added here with a link to your website.
<a href="https://opencollective.com/coreui/contribute/platinum-sponsor-40959/checkout"><img src="https://opencollective.com/coreui/tiers/platinum-sponsor/0/avatar.svg?avatarHeight=100"></a>
### Gold Sponsors
Support this project by [becoming a Gold Sponsor](https://opencollective.com/coreui/contribute/gold-sponsor-40960/). A big company logo will be added here with a link to your website.
<a href="https://opencollective.com/coreui/contribute/gold-sponsor-40960/checkout"><img src="https://opencollective.com/coreui/tiers/gold-sponsor/0/avatar.svg?avatarHeight=100"></a>
### Silver Sponsors
Support this project by [becoming a Silver Sponsor](https://opencollective.com/coreui/contribute/silver-sponsor-40967/). A medium company logo will be added here with a link to your website.
<a href="https://opencollective.com/coreui/contribute/silver-sponsor-40967/checkout"><img src="https://opencollective.com/coreui/tiers/gold-sponsor/0/avatar.svg?avatarHeight=100"></a>
### Bronze Sponsors
Support this project by [becoming a Bronze Sponsor](https://opencollective.com/coreui/contribute/bronze-sponsor-40966/). The company avatar will show up here with a link to your OpenCollective Profile.
<a href="https://opencollective.com/coreui/contribute/bronze-sponsor-40966/checkout"><img src="https://opencollective.com/coreui/tiers/bronze-sponsor/0/avatar.svg?avatarHeight=100"></a>
### Backers
Thanks to all the backers and sponsors! Support this project by [becoming a backer](https://opencollective.com/coreui/contribute/backer-40965/).
<a href="https://opencollective.com/coreui/contribute/backer-40965/checkout" target="_blank" rel="noopener"><img src="https://opencollective.com/coreui/backers.svg?width=890"></a>
<!--- EndOpenCollectiveBackers -->
## Copyright and License
copyright 2022 creativeLabs Łukasz Holeczek.
Code released under [the MIT license](https://github.com/coreui/coreui-free-react-admin-template/blob/master/LICENSE).
There is only one limitation you can't cant re-distribute the CoreUI as stock. You cant do this if you modify the CoreUI. In past we faced some problems with persons who tried to sell CoreUI based templates.

3
frontend/babel.config.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
}

3
frontend/cypress.json Normal file
View file

@ -0,0 +1,3 @@
{
"pluginsFile": "tests/e2e/plugins/index.js"
}

10
frontend/frontend.go Normal file
View file

@ -0,0 +1,10 @@
package frontend
import (
"embed"
)
//go:generate npm run build
//go:embed dist
var FrontEndFiles embed.FS

3
frontend/jest.config.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
}

19
frontend/jsconfig.json Normal file
View file

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

View file

@ -0,0 +1,7 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "6.0.1"
}
}

27585
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

75
frontend/package.json Normal file
View file

@ -0,0 +1,75 @@
{
"name": "@coreui/coreui-free-vue-admin-template",
"version": "4.1.0",
"description": "CoreUI Free Vue Admin Template",
"author": "The CoreUI Team (https://github.com/orgs/coreui/people)",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
"lint": "vue-cli-service lint",
"generate": "openapi --input http://localhost:8888/openapi.json --output ./src/generated --client axios --useOptions --exportSchemas true"
},
"dependencies": {
"@coreui/chartjs": "^3.0.0",
"@coreui/coreui": "^4.1.0",
"@coreui/icons": "^2.1.0",
"@coreui/icons-vue": "2.0.0",
"@coreui/utils": "^1.3.1",
"@coreui/vue": "^4.1.0",
"@coreui/vue-chartjs": "2.0.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"axios": "^0.27.2",
"core-js": "^3.19.0",
"vue": "^3.2.37",
"vue-class-component": "^8.0.0-0",
"vue-router": "^4.0.12",
"vuex": "^4.0.2",
"yup": "^0.32.11"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@types/jest": "^27.0.1",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "~5.0.0-rc.1",
"@vue/cli-plugin-e2e-cypress": "~5.0.0-rc.1",
"@vue/cli-plugin-eslint": "~5.0.0-rc.1",
"@vue/cli-plugin-router": "~5.0.0-rc.1",
"@vue/cli-plugin-typescript": "~5.0.0",
"@vue/cli-plugin-unit-jest": "~5.0.0-rc.1",
"@vue/cli-plugin-vuex": "~5.0.0-rc.1",
"@vue/cli-service": "~5.0.0-rc.1",
"@vue/eslint-config-typescript": "^9.1.0",
"@vue/test-utils": "^2.0.0-0",
"@vue/vue3-jest": "^27.0.0-alpha.1",
"babel-jest": "^27.0.6",
"cypress": "^8.7.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.0.3",
"form-data": "^4.0.0",
"jest": "^27.0.5",
"openapi-typescript-codegen": "^0.23.0",
"prettier": "^2.4.1",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"ts-jest": "^27.0.4",
"typescript": "~4.5.5"
},
"bugs": {
"url": "https://github.com/coreui/coreui-free-vue-admin-template/issues"
},
"config": {
"coreui_library_short_version": "4.1"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git@github.com:coreui/coreui-free-vue-admin-template.git"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<!--
* MouthPiece Messaging Server
* @version v1.0
* @link https://coreui.io/vue/
* Copyright (c) 2021 creativeLabs Łukasz Holeczek
* License (https://coreui.io/pro/license)
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0,shrink-to-fit=no">
<meta name="description" content="MouthPiece Messaging Server">
<meta name="author" content="creativeLabs Łukasz Holeczek">
<title>MouthPiece Messaging Server</title>
<!-- favicons for all devices -->
<link rel="apple-touch-icon" sizes="57x57" href="<%= BASE_URL %>apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="<%= BASE_URL %>apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="<%= BASE_URL %>apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="<%= BASE_URL %>apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="<%= BASE_URL %>apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="<%= BASE_URL %>apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="<%= BASE_URL %>apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="<%= BASE_URL %>apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="<%= BASE_URL %>apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="<%= BASE_URL %>android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="<%= BASE_URL %>favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="<%= BASE_URL %>favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="<%= BASE_URL %>favicon-16x16.png">
<link rel="manifest" href="<%= BASE_URL %>manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
</head>
<body>
<noscript>
<strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View file

@ -71,9 +71,9 @@ function login(prov) {
});
}
function loginAnonymously(username) {
return fetch(
`/auth/anonymous/login?id=auth-example&user=${encodeURIComponent(username)}`
function loginAnonymously(username, password) {
return req(
`/auth/direct/login?id=auth-example&user=${encodeURIComponent(username)}&passwd=${encodeURIComponent(password)}`
);
}
@ -89,7 +89,7 @@ function loginViaEmailToken(token) {
return req(`/auth/email/login?token=${token}`);
}
const validUsernameRegex = /^[a-zA-Z][\w ]+$/;
const validUsernameRegex = /[^@]+@[^\.]+\..+/;
function getUsernameInvalidReason(username) {
if (username.length < 3) return "Username must be at least 3 characters long";
@ -120,6 +120,11 @@ function getAnonymousLoginForm(onSubmit) {
input.placeholder = "Username";
input.className = "anon-form__input";
const pass = document.createElement("input");
pass.type = "text";
pass.placeholder = "Password";
pass.className = "anon-form__input";
const submit = document.createElement("input");
submit.type = "submit";
submit.value = "Log in";
@ -143,11 +148,12 @@ function getAnonymousLoginForm(onSubmit) {
});
form.appendChild(input);
form.appendChild(pass);
form.appendChild(submit);
form.addEventListener("submit", e => {
e.preventDefault();
onSubmit(input.value);
onSubmit(input.value, pass.value);
});
return form;
@ -330,7 +336,7 @@ function getLoginLinks() {
return getProviders().then(providers =>
providers.map(prov => {
let a;
if (prov === "anonymous") {
if (prov === "direct") {
a = document.createElement("span");
a.dataset.provider = prov;
a.className = "login__prov";
@ -355,8 +361,8 @@ function getLoginLinks() {
}
});
const form = getAnonymousLoginForm(username => {
loginAnonymously(username)
const form = getAnonymousLoginForm((username, password) => {
loginAnonymously(username, password)
.then(() => {
window.location.replace(window.location.href);
})

View file

@ -0,0 +1,41 @@
{
"name": "CoreUI Free Vue Admin Template",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

8
frontend/src/App.vue Normal file
View file

@ -0,0 +1,8 @@
<template>
<router-view />
</template>
<style lang="scss">
// Import Main styles for this application
@import 'styles/style';
</style>

58
frontend/src/_nav.js Normal file
View file

@ -0,0 +1,58 @@
export default [
{
component: 'CNavItem',
name: 'Dashboard',
to: '/dashboard',
icon: 'cil-speedometer',
},
{
component: 'CNavTitle',
name: 'Apps',
},
{
component: 'CNavItem',
name: 'Applications',
to: '/apps',
icon: 'cil-puzzle',
},
{
component: 'CNavTitle',
name: 'Users',
},
{
component: 'CNavItem',
name: 'Users',
to: '/users',
icon: 'cil-puzzle',
},
{
component: 'CNavTitle',
name: 'Transports',
},
{
component: 'CNavItem',
name: 'Transports',
to: '/transports',
icon: 'cil-cursor',
},
{
component: 'CNavTitle',
name: 'Notifications',
},
{
component: 'CNavItem',
name: 'Notifications',
to: '/notifications',
icon: 'cil-bell',
},
{
component: 'CNavTitle',
name: 'Settings',
},
{
component: 'CNavItem',
name: 'Settings',
to: '/settings',
icon: 'cil-star',
},
]

View file

@ -0,0 +1,31 @@
export const logoNegative = [
'556 134',
`
<title>coreui vue logo</title>
<g>
<g style="fill:#1bbd93">
<path class="cls-1" d="M347.9818,90.0869l-11.84-43.52-.0644-.1924q0-.5112.6406-.5117h1.2793a.66.66,0,0,1,.7051.5762l10.623,39.68c.042.0859.0859.1279.1289.1279.041,0,.084-.042.127-.1279l10.625-39.68a.657.657,0,0,1,.7031-.5762h1.2168a.54.54,0,0,1,.5762.7041l-11.9043,43.52a.6584.6584,0,0,1-.7041.5761h-1.4082A.6577.6577,0,0,1,347.9818,90.0869Z"/>
<path class="cls-1" d="M382.2786,89.5751a10.9023,10.9023,0,0,1-4.3515-4.5439,14.4586,14.4586,0,0,1-1.5362-6.7842V46.5029a.5656.5656,0,0,1,.64-.64h1.2168a.5659.5659,0,0,1,.64.64v32a10.5488,10.5488,0,0,0,2.72,7.5527,10.36,10.36,0,0,0,14.3359,0,10.5493,10.5493,0,0,0,2.7207-7.5527v-32a.5655.5655,0,0,1,.64-.64h1.2159a.5666.5666,0,0,1,.6406.64V78.247a13.01,13.01,0,0,1-3.3926,9.376,11.8974,11.8974,0,0,1-9.0234,3.5527A12.8481,12.8481,0,0,1,382.2786,89.5751Z"/>
<path class="cls-1" d="M439.5843,48.1035H419.5521a.2263.2263,0,0,0-.2559.2558V66.8554a.2259.2259,0,0,0,.2559.2559h13.8242a.5665.5665,0,0,1,.6406.64v.96a.5665.5665,0,0,1-.6406.6406H419.5521a.2263.2263,0,0,0-.2559.2559v18.56a.2259.2259,0,0,0,.2559.2559h20.0322a.5665.5665,0,0,1,.64.6406v.96a.5655.5655,0,0,1-.64.64H417.4407a.5654.5654,0,0,1-.6406-.64v-43.52a.5658.5658,0,0,1,.6406-.64h22.1436a.5659.5659,0,0,1,.64.64v.96A.5658.5658,0,0,1,439.5843,48.1035Z"/>
<path class="cls-1" d="M454.5921,89.5117a2.8385,2.8385,0,0,1-.8-2.0489,2.9193,2.9193,0,0,1,.8-2.1113,2.7518,2.7518,0,0,1,2.0791-.832,2.8465,2.8465,0,0,1,2.9443,2.9433,2.7561,2.7561,0,0,1-.832,2.08,2.9208,2.9208,0,0,1-2.1123.8008A2.7521,2.7521,0,0,1,454.5921,89.5117Z"/>
<path class="cls-1" d="M474.931,88.0078a11.3087,11.3087,0,0,1-3.2-8.4161v-5.44a.5655.5655,0,0,1,.64-.64h1.2158a.5662.5662,0,0,1,.6407.64v5.5039a9.1421,9.1421,0,0,0,2.5283,6.72,8.9734,8.9734,0,0,0,6.6875,2.5606,8.7916,8.7916,0,0,0,9.28-9.28V46.5029a.5655.5655,0,0,1,.64-.64h1.2158a.5656.5656,0,0,1,.64.64V79.5917a11.2541,11.2541,0,0,1-3.2315,8.4161,13.0621,13.0621,0,0,1-17.0556,0Z"/>
<path class="cls-1" d="M512.8753,88.1035a10.4847,10.4847,0,0,1-3.36-8.128v-1.792a.5665.5665,0,0,1,.6406-.6406h1.0879a.5666.5666,0,0,1,.64.6406v1.6a8.5461,8.5461,0,0,0,2.752,6.6563,10.5361,10.5361,0,0,0,7.36,2.4961,9.8741,9.8741,0,0,0,6.9766-2.3682,8.2188,8.2188,0,0,0,2.56-6.3359,8.3952,8.3952,0,0,0-1.12-4.416,11.3752,11.3752,0,0,0-3.3281-3.3926,71.6866,71.6866,0,0,0-6.1758-3.7119,71.0151,71.0151,0,0,1-6.24-3.84,12.1824,12.1824,0,0,1-3.4238-3.68,10.2659,10.2659,0,0,1-1.28-5.3437,9.86,9.86,0,0,1,3.0723-7.7441,12.0126,12.0126,0,0,1,8.3193-2.752q5.6969,0,8.9609,3.1035a10.8247,10.8247,0,0,1,3.2637,8.2246v1.6a.5658.5658,0,0,1-.6406.64h-1.1514a.5651.5651,0,0,1-.64-.64V56.8076a8.8643,8.8643,0,0,0-2.6241-6.6885,9.9936,9.9936,0,0,0-7.2324-2.5274,9.37,9.37,0,0,0-6.5283,2.1436,7.8253,7.8253,0,0,0-2.3672,6.1123,7.8088,7.8088,0,0,0,1.0235,4.16,10.3978,10.3978,0,0,0,3.0078,3.039,63.0249,63.0249,0,0,0,5.9521,3.4883,70.7955,70.7955,0,0,1,6.72,4.2559,13.4613,13.4613,0,0,1,3.6485,3.9365,10.044,10.044,0,0,1,1.28,5.1836,10.7185,10.7185,0,0,1-3.2647,8.1924q-3.2637,3.0717-8.832,3.0722Q516.2342,91.1757,512.8753,88.1035Z"/>
</g>
</g>
<g style="fill: currentColor">
<g>
<path d="M99.835,36.0577l-39-22.5167a12,12,0,0,0-12,0l-39,22.5166a12.0339,12.0339,0,0,0-6,10.3924V91.4833a12.0333,12.0333,0,0,0,6,10.3923l39,22.5167a12,12,0,0,0,12,0l39-22.5167a12.0331,12.0331,0,0,0,6-10.3923V46.45A12.0334,12.0334,0,0,0,99.835,36.0577Zm-2,55.4256a4,4,0,0,1-2,3.4641l-39,22.5167a4.0006,4.0006,0,0,1-4,0l-39-22.5167a4,4,0,0,1-2-3.4641V46.45a4,4,0,0,1,2-3.4642l39-22.5166a4,4,0,0,1,4,0l39,22.5166a4,4,0,0,1,2,3.4642Z"/>
<path d="M77.8567,82.0046h-2.866a4,4,0,0,0-1.9247.4934L55.7852,91.9833,35.835,80.4648V57.4872l19.95-11.5185,17.2893,9.4549a3.9993,3.9993,0,0,0,1.9192.4906h2.8632a2,2,0,0,0,2-2V51.2024a2,2,0,0,0-1.04-1.7547L59.628,38.9521a8.0391,8.0391,0,0,0-7.8428.09L31.8346,50.56a8.0246,8.0246,0,0,0-4,6.9287v22.976a8,8,0,0,0,4,6.9283l19.95,11.5186a8.0429,8.0429,0,0,0,7.8433.0879l19.19-10.5312a2,2,0,0,0,1.0378-1.7533v-2.71A2,2,0,0,0,77.8567,82.0046Z"/>
</g>
<g>
<path d="M172.58,45.3618a15.0166,15.0166,0,0,0-15,14.9995V77.6387a15,15,0,0,0,30,0V60.3613A15.0166,15.0166,0,0,0,172.58,45.3618Zm7,32.2769a7,7,0,0,1-14,0V60.3613a7,7,0,0,1,14,0Z"/>
<path d="M135.9138,53.4211a7.01,7.01,0,0,1,7.8681,6.0752.9894.9894,0,0,0,.9843.865h6.03a1.0108,1.0108,0,0,0,.9987-1.0971,15.0182,15.0182,0,0,0-15.7162-13.8837,15.2881,15.2881,0,0,0-14.2441,15.4163V77.2037A15.288,15.288,0,0,0,136.0792,92.62a15.0183,15.0183,0,0,0,15.7162-13.8842,1.0107,1.0107,0,0,0-.9987-1.0971h-6.03a.9894.9894,0,0,0-.9843.865,7.01,7.01,0,0,1-7.8679,6.0757,7.1642,7.1642,0,0,1-6.0789-7.1849V60.6057A7.1638,7.1638,0,0,1,135.9138,53.4211Z"/>
<path d="M218.7572,72.9277a12.1585,12.1585,0,0,0,7.1843-11.0771V58.1494A12.1494,12.1494,0,0,0,213.7921,46H196.835a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V74h6.6216l7.9154,17.4138a1,1,0,0,0,.91.5862h6.5911a1,1,0,0,0,.91-1.4138Zm-.8157-11.0771A4.1538,4.1538,0,0,1,213.7926,66h-9.8511V54h9.8511a4.1538,4.1538,0,0,1,4.1489,4.1494Z"/>
<path d="M260.835,46h-26a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h26a1,1,0,0,0,1-1V85a1,1,0,0,0-1-1h-19V72h13a1,1,0,0,0,1-1V65a1,1,0,0,0-1-1h-13V54h19a1,1,0,0,0,1-1V47A1,1,0,0,0,260.835,46Z"/>
<path d="M298.835,46h-6a1,1,0,0,0-1,1V69.6475a7.0066,7.0066,0,1,1-14,0V47a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1V69.6475a15.0031,15.0031,0,1,0,30,0V47A1,1,0,0,0,298.835,46Z"/>
<rect x="307.835" y="46" width="8" height="38" rx="1"/>
</g>
</g>
</g>
`,
]

View file

@ -0,0 +1,30 @@
export const logo = [
'556 134',
`
<title>coreui vue</title>
<g>
<g style="fill:#1bbd93">
<path class="cls-1" d="M347.9818,90.0869l-11.84-43.52-.0644-.1924q0-.5112.6406-.5117h1.2793a.66.66,0,0,1,.7051.5762l10.623,39.68c.042.0859.0859.1279.1289.1279.041,0,.084-.042.127-.1279l10.625-39.68a.657.657,0,0,1,.7031-.5762h1.2168a.54.54,0,0,1,.5762.7041l-11.9043,43.52a.6584.6584,0,0,1-.7041.5761h-1.4082A.6577.6577,0,0,1,347.9818,90.0869Z"/>
<path class="cls-1" d="M382.2786,89.5751a10.9023,10.9023,0,0,1-4.3515-4.5439,14.4586,14.4586,0,0,1-1.5362-6.7842V46.5029a.5656.5656,0,0,1,.64-.64h1.2168a.5659.5659,0,0,1,.64.64v32a10.5488,10.5488,0,0,0,2.72,7.5527,10.36,10.36,0,0,0,14.3359,0,10.5493,10.5493,0,0,0,2.7207-7.5527v-32a.5655.5655,0,0,1,.64-.64h1.2159a.5666.5666,0,0,1,.6406.64V78.247a13.01,13.01,0,0,1-3.3926,9.376,11.8974,11.8974,0,0,1-9.0234,3.5527A12.8481,12.8481,0,0,1,382.2786,89.5751Z"/>
<path class="cls-1" d="M439.5843,48.1035H419.5521a.2263.2263,0,0,0-.2559.2558V66.8554a.2259.2259,0,0,0,.2559.2559h13.8242a.5665.5665,0,0,1,.6406.64v.96a.5665.5665,0,0,1-.6406.6406H419.5521a.2263.2263,0,0,0-.2559.2559v18.56a.2259.2259,0,0,0,.2559.2559h20.0322a.5665.5665,0,0,1,.64.6406v.96a.5655.5655,0,0,1-.64.64H417.4407a.5654.5654,0,0,1-.6406-.64v-43.52a.5658.5658,0,0,1,.6406-.64h22.1436a.5659.5659,0,0,1,.64.64v.96A.5658.5658,0,0,1,439.5843,48.1035Z"/>
<path class="cls-1" d="M454.5921,89.5117a2.8385,2.8385,0,0,1-.8-2.0489,2.9193,2.9193,0,0,1,.8-2.1113,2.7518,2.7518,0,0,1,2.0791-.832,2.8465,2.8465,0,0,1,2.9443,2.9433,2.7561,2.7561,0,0,1-.832,2.08,2.9208,2.9208,0,0,1-2.1123.8008A2.7521,2.7521,0,0,1,454.5921,89.5117Z"/>
<path class="cls-1" d="M474.931,88.0078a11.3087,11.3087,0,0,1-3.2-8.4161v-5.44a.5655.5655,0,0,1,.64-.64h1.2158a.5662.5662,0,0,1,.6407.64v5.5039a9.1421,9.1421,0,0,0,2.5283,6.72,8.9734,8.9734,0,0,0,6.6875,2.5606,8.7916,8.7916,0,0,0,9.28-9.28V46.5029a.5655.5655,0,0,1,.64-.64h1.2158a.5656.5656,0,0,1,.64.64V79.5917a11.2541,11.2541,0,0,1-3.2315,8.4161,13.0621,13.0621,0,0,1-17.0556,0Z"/>
<path class="cls-1" d="M512.8753,88.1035a10.4847,10.4847,0,0,1-3.36-8.128v-1.792a.5665.5665,0,0,1,.6406-.6406h1.0879a.5666.5666,0,0,1,.64.6406v1.6a8.5461,8.5461,0,0,0,2.752,6.6563,10.5361,10.5361,0,0,0,7.36,2.4961,9.8741,9.8741,0,0,0,6.9766-2.3682,8.2188,8.2188,0,0,0,2.56-6.3359,8.3952,8.3952,0,0,0-1.12-4.416,11.3752,11.3752,0,0,0-3.3281-3.3926,71.6866,71.6866,0,0,0-6.1758-3.7119,71.0151,71.0151,0,0,1-6.24-3.84,12.1824,12.1824,0,0,1-3.4238-3.68,10.2659,10.2659,0,0,1-1.28-5.3437,9.86,9.86,0,0,1,3.0723-7.7441,12.0126,12.0126,0,0,1,8.3193-2.752q5.6969,0,8.9609,3.1035a10.8247,10.8247,0,0,1,3.2637,8.2246v1.6a.5658.5658,0,0,1-.6406.64h-1.1514a.5651.5651,0,0,1-.64-.64V56.8076a8.8643,8.8643,0,0,0-2.6241-6.6885,9.9936,9.9936,0,0,0-7.2324-2.5274,9.37,9.37,0,0,0-6.5283,2.1436,7.8253,7.8253,0,0,0-2.3672,6.1123,7.8088,7.8088,0,0,0,1.0235,4.16,10.3978,10.3978,0,0,0,3.0078,3.039,63.0249,63.0249,0,0,0,5.9521,3.4883,70.7955,70.7955,0,0,1,6.72,4.2559,13.4613,13.4613,0,0,1,3.6485,3.9365,10.044,10.044,0,0,1,1.28,5.1836,10.7185,10.7185,0,0,1-3.2647,8.1924q-3.2637,3.0717-8.832,3.0722Q516.2342,91.1757,512.8753,88.1035Z"/>
</g>
<g style="fill:#3c4b64">
<g>
<path d="M99.835,36.0577l-39-22.5167a12,12,0,0,0-12,0l-39,22.5166a12.0339,12.0339,0,0,0-6,10.3924V91.4833a12.0333,12.0333,0,0,0,6,10.3923l39,22.5167a12,12,0,0,0,12,0l39-22.5167a12.0331,12.0331,0,0,0,6-10.3923V46.45A12.0334,12.0334,0,0,0,99.835,36.0577Zm-2,55.4256a4,4,0,0,1-2,3.4641l-39,22.5167a4.0006,4.0006,0,0,1-4,0l-39-22.5167a4,4,0,0,1-2-3.4641V46.45a4,4,0,0,1,2-3.4642l39-22.5166a4,4,0,0,1,4,0l39,22.5166a4,4,0,0,1,2,3.4642Z"/>
<path d="M77.8567,82.0046h-2.866a4,4,0,0,0-1.9247.4934L55.7852,91.9833,35.835,80.4648V57.4872l19.95-11.5185,17.2893,9.4549a3.9993,3.9993,0,0,0,1.9192.4906h2.8632a2,2,0,0,0,2-2V51.2024a2,2,0,0,0-1.04-1.7547L59.628,38.9521a8.0391,8.0391,0,0,0-7.8428.09L31.8346,50.56a8.0246,8.0246,0,0,0-4,6.9287v22.976a8,8,0,0,0,4,6.9283l19.95,11.5186a8.0429,8.0429,0,0,0,7.8433.0879l19.19-10.5312a2,2,0,0,0,1.0378-1.7533v-2.71A2,2,0,0,0,77.8567,82.0046Z"/>
</g>
<g>
<path d="M172.58,45.3618a15.0166,15.0166,0,0,0-15,14.9995V77.6387a15,15,0,0,0,30,0V60.3613A15.0166,15.0166,0,0,0,172.58,45.3618Zm7,32.2769a7,7,0,0,1-14,0V60.3613a7,7,0,0,1,14,0Z"/>
<path d="M135.9138,53.4211a7.01,7.01,0,0,1,7.8681,6.0752.9894.9894,0,0,0,.9843.865h6.03a1.0108,1.0108,0,0,0,.9987-1.0971,15.0182,15.0182,0,0,0-15.7162-13.8837,15.2881,15.2881,0,0,0-14.2441,15.4163V77.2037A15.288,15.288,0,0,0,136.0792,92.62a15.0183,15.0183,0,0,0,15.7162-13.8842,1.0107,1.0107,0,0,0-.9987-1.0971h-6.03a.9894.9894,0,0,0-.9843.865,7.01,7.01,0,0,1-7.8679,6.0757,7.1642,7.1642,0,0,1-6.0789-7.1849V60.6057A7.1638,7.1638,0,0,1,135.9138,53.4211Z"/>
<path d="M218.7572,72.9277a12.1585,12.1585,0,0,0,7.1843-11.0771V58.1494A12.1494,12.1494,0,0,0,213.7921,46H196.835a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V74h6.6216l7.9154,17.4138a1,1,0,0,0,.91.5862h6.5911a1,1,0,0,0,.91-1.4138Zm-.8157-11.0771A4.1538,4.1538,0,0,1,213.7926,66h-9.8511V54h9.8511a4.1538,4.1538,0,0,1,4.1489,4.1494Z"/>
<path d="M260.835,46h-26a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h26a1,1,0,0,0,1-1V85a1,1,0,0,0-1-1h-19V72h13a1,1,0,0,0,1-1V65a1,1,0,0,0-1-1h-13V54h19a1,1,0,0,0,1-1V47A1,1,0,0,0,260.835,46Z"/>
<path d="M298.835,46h-6a1,1,0,0,0-1,1V69.6475a7.0066,7.0066,0,1,1-14,0V47a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1V69.6475a15.0031,15.0031,0,1,0,30,0V47A1,1,0,0,0,298.835,46Z"/>
<rect x="307.835" y="46" width="8" height="38" rx="1"/>
</g>
</g>
</g>
`,
]

View file

@ -0,0 +1,12 @@
export const sygnet = [
'160 160',
`
<title>coreui logo</title>
<g>
<g style="fill:#fff;">
<path d="M125,47.091,86,24.5743a12,12,0,0,0-12,0L35,47.091a12.0336,12.0336,0,0,0-6,10.3923v45.0334a12.0335,12.0335,0,0,0,6,10.3923l39,22.5166a11.9993,11.9993,0,0,0,12,0l39-22.5166a12.0335,12.0335,0,0,0,6-10.3923V57.4833A12.0336,12.0336,0,0,0,125,47.091Zm-2,55.4257a4,4,0,0,1-2,3.464L82,128.4974a4,4,0,0,1-4,0L39,105.9807a4,4,0,0,1-2-3.464V57.4833a4,4,0,0,1,2-3.4641L78,31.5025a4,4,0,0,1,4,0l39,22.5167a4,4,0,0,1,2,3.4641Z"/>
<path d="M103.0216,93.0379h-2.866a4,4,0,0,0-1.9246.4935L80.95,103.0167,61,91.4981V68.5206L80.95,57.002l17.2894,9.455a4,4,0,0,0,1.9192.4905h2.8632a2,2,0,0,0,2-2V62.2357a2,2,0,0,0-1.04-1.7547L84.793,49.9854a8.0391,8.0391,0,0,0-7.8428.09L57,61.5929A8.0243,8.0243,0,0,0,53,68.5216v22.976a8,8,0,0,0,4,6.9283l19.95,11.5185a8.0422,8.0422,0,0,0,7.8433.0879l19.19-10.5311a2,2,0,0,0,1.0378-1.7534v-2.71A2,2,0,0,0,103.0216,93.0379Z"/>
</g>
</g>
`,
]

View file

@ -0,0 +1,171 @@
import {
cibFacebook,
cibTwitter,
cibLinkedin,
cibFlickr,
cibTumblr,
cibXing,
cibGithub,
cibGoogle,
cibStackoverflow,
cibYoutube,
cibDribbble,
cibInstagram,
cibPinterest,
cibVk,
cibYahoo,
cibBehance,
cibReddit,
cibVimeo,
cibCcMastercard,
cibCcVisa,
cibCcStripe,
cibCcPaypal,
cibCcApplePay,
cibCcAmex,
} from '@coreui/icons'
import { cifUs, cifBr, cifIn, cifFr, cifEs, cifPl } from '@coreui/icons'
import {
cilArrowBottom,
cilArrowRight,
cilArrowTop,
cilBan,
cilBasket,
cilBell,
cilCalculator,
cilCalendar,
cilCloudDownload,
cilChartPie,
cilCheck,
cilChevronBottom,
cilChevronTop,
cilCheckCircle,
cilCode,
cilCommentSquare,
cilCursor,
cilDrop,
cilDollar,
cilEnvelopeClosed,
cilEnvelopeOpen,
cilEuro,
cilGlobeAlt,
cilGrid,
cilFile,
cilJustifyCenter,
cilLaptop,
cilLayers,
cilLightbulb,
cilList,
cilLocationPin,
cilLockLocked,
cilMagnifyingGlass,
cilMediaPlay,
cilMenu,
cilMoon,
cilNotes,
cilOptions,
cilPencil,
cilPeople,
cilPuzzle,
cilSettings,
cilShieldAlt,
cilSpeech,
cilSpeedometer,
cilStar,
cilTask,
cilUser,
cilUserFemale,
cilUserFollow,
cilXCircle,
} from '@coreui/icons'
export const iconsSet = Object.assign(
{},
{
cilArrowBottom,
cilArrowRight,
cilArrowTop,
cilBan,
cilBasket,
cilBell,
cilCalculator,
cilCalendar,
cilCloudDownload,
cilChartPie,
cilCheck,
cilChevronBottom,
cilChevronTop,
cilCheckCircle,
cilCode,
cilCommentSquare,
cilCursor,
cilDrop,
cilDollar,
cilEnvelopeClosed,
cilEnvelopeOpen,
cilEuro,
cilGlobeAlt,
cilGrid,
cilFile,
cilJustifyCenter,
cilLaptop,
cilLayers,
cilLightbulb,
cilList,
cilLocationPin,
cilLockLocked,
cilMagnifyingGlass,
cilMediaPlay,
cilMenu,
cilMoon,
cilNotes,
cilOptions,
cilPencil,
cilPeople,
cilPuzzle,
cilSettings,
cilShieldAlt,
cilSpeech,
cilSpeedometer,
cilStar,
cilTask,
cilUser,
cilUserFemale,
cilUserFollow,
cilXCircle,
},
{
cifUs,
cifBr,
cifIn,
cifFr,
cifEs,
cifPl,
},
{
cibFacebook,
cibTwitter,
cibLinkedin,
cibFlickr,
cibTumblr,
cibXing,
cibGithub,
cibGoogle,
cibStackoverflow,
cibYoutube,
cibDribbble,
cibInstagram,
cibPinterest,
cibVk,
cibYahoo,
cibBehance,
cibReddit,
cibVimeo,
cibCcMastercard,
cibCcVisa,
cibCcStripe,
cibCcPaypal,
cibCcApplePay,
cibCcAmex,
},
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -0,0 +1,46 @@
<template>
<CBreadcrumb class="d-md-down-none me-auto mb-0">
<CBreadcrumbItem
v-for="item in breadcrumbs"
:key="item"
:href="item.active ? '' : item.path"
:active="item.active"
>
{{ item.name }}
</CBreadcrumbItem>
</CBreadcrumb>
</template>
<script>
import { onMounted, ref } from 'vue'
import router from '@/router'
export default {
name: 'AppBreadcrumb',
setup() {
const breadcrumbs = ref()
const getBreadcrumbs = () => {
return router.currentRoute.value.matched.map((route) => {
return {
active: route.path === router.currentRoute.value.fullPath,
name: route.name,
path: `${router.options.history.base}${route.path}`,
}
})
}
router.afterEach(() => {
breadcrumbs.value = getBreadcrumbs()
})
onMounted(() => {
breadcrumbs.value = getBreadcrumbs()
})
return {
breadcrumbs,
}
},
}
</script>

View file

@ -0,0 +1,20 @@
<template>
<CFooter>
<div>
<a href="https://github.com/Fishwaldo/mouthpiece" target="_blank">MouthPiece</a>
<span class="ms-1"
>&copy; {{ new Date().getFullYear() }} Justin Hammond.</span
>
</div>
<div class="ms-auto">
<span class="me-1" target="_blank">Powered by</span>
<a href="https://coreui.io/vue">CoreUI for Vue</a>
</div>
</CFooter>
</template>
<script>
export default {
name: 'AppFooter',
}
</script>

View file

@ -0,0 +1,63 @@
<template>
<CHeader position="sticky" class="mb-4">
<CContainer fluid>
<CHeaderToggler class="ps-1" @click="$store.commit('toggleSidebar')">
<CIcon icon="cil-menu" size="lg" />
</CHeaderToggler>
<CHeaderBrand class="mx-auto d-lg-none" to="/">
<CIcon :icon="logo" height="48" alt="Logo" />
</CHeaderBrand>
<CHeaderNav class="d-none d-md-flex me-auto">
<CNavItem>
<CNavLink href="/dashboard"> Dashboard </CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">Users</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">Settings</CNavLink>
</CNavItem>
</CHeaderNav>
<CHeaderNav>
<CNavItem>
<CNavLink href="#">
<CIcon class="mx-2" icon="cil-bell" size="lg" />
</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">
<CIcon class="mx-2" icon="cil-list" size="lg" />
</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">
<CIcon class="mx-2" icon="cil-envelope-open" size="lg" />
</CNavLink>
</CNavItem>
<AppHeaderDropdownAccnt />
</CHeaderNav>
</CContainer>
<CHeaderDivider />
<CContainer fluid>
<AppBreadcrumb />
</CContainer>
</CHeader>
</template>
<script>
import AppBreadcrumb from './AppBreadcrumb'
import AppHeaderDropdownAccnt from './AppHeaderDropdownAccnt'
import { logo } from '@/assets/brand/logo'
export default {
name: 'AppHeader',
components: {
AppBreadcrumb,
AppHeaderDropdownAccnt,
},
setup() {
return {
logo,
}
},
}
</script>

View file

@ -0,0 +1,64 @@
<template>
<CDropdown variant="nav-item">
<CDropdownToggle placement="bottom-end" class="py-0" :caret="false">
<CAvatar :src="avatar" size="md" />
</CDropdownToggle>
<CDropdownMenu class="pt-0">
<CDropdownHeader component="h6" class="bg-light fw-semibold py-2">
Account
</CDropdownHeader>
<CDropdownItem>
<CIcon icon="cil-bell" /> Updates
<CBadge color="info" class="ms-auto">{{ itemsCount }}</CBadge>
</CDropdownItem>
<CDropdownItem>
<CIcon icon="cil-envelope-open" /> Messages
<CBadge color="success" class="ms-auto">{{ itemsCount }}</CBadge>
</CDropdownItem>
<CDropdownItem>
<CIcon icon="cil-task" /> Tasks
<CBadge color="danger" class="ms-auto">{{ itemsCount }}</CBadge>
</CDropdownItem>
<CDropdownItem>
<CIcon icon="cil-comment-square" /> Comments
<CBadge color="warning" class="ms-auto">{{ itemsCount }}</CBadge>
</CDropdownItem>
<CDropdownHeader component="h6" class="bg-light fw-semibold py-2">
Settings
</CDropdownHeader>
<CDropdownItem> <CIcon icon="cil-user" /> Profile </CDropdownItem>
<CDropdownItem> <CIcon icon="cil-settings" /> Settings </CDropdownItem>
<CDropdownItem>
<CIcon icon="cil-dollar" /> Payments
<CBadge color="secondary" class="ms-auto">{{ itemsCount }}</CBadge>
</CDropdownItem>
<CDropdownItem>
<CIcon icon="cil-file" /> Projects
<CBadge color="primary" class="ms-auto">{{ itemsCount }}</CBadge>
</CDropdownItem>
<CDropdownDivider />
<CDropdownItem>
<CIcon icon="cil-shield-alt" /> Lock Account
</CDropdownItem>
<CDropdownItem @click="logout"> <CIcon icon="cil-lock-locked" /> Logout </CDropdownItem>
</CDropdownMenu>
</CDropdown>
</template>
<script>
import avatar from '@/assets/images/avatars/8.jpg'
export default {
name: 'AppHeaderDropdownAccnt',
setup() {
return {
avatar: avatar,
itemsCount: 42,
}
},
methods: {
logout() {
this.$store.dispatch('auth/logout')
},
},
}
</script>

View file

@ -0,0 +1,55 @@
<template>
<CSidebar
position="fixed"
:unfoldable="sidebarUnfoldable"
:visible="sidebarVisible"
@visible-change="
(event) =>
$store.commit({
type: 'updateSidebarVisible',
value: event,
})
"
>
<CSidebarBrand>
<CIcon
custom-class-name="sidebar-brand-full"
:icon="logoNegative"
:height="35"
/>
<CIcon
custom-class-name="sidebar-brand-narrow"
:icon="sygnet"
:height="35"
/>
</CSidebarBrand>
<AppSidebarNav />
<CSidebarToggler
class="d-none d-lg-flex"
@click="$store.commit('toggleUnfoldable')"
/>
</CSidebar>
</template>
<script>
import { computed } from 'vue'
import { useStore } from 'vuex'
import { AppSidebarNav } from './AppSidebarNav'
import { logoNegative } from '@/assets/brand/logo-negative'
import { sygnet } from '@/assets/brand/sygnet'
export default {
name: 'AppSidebar',
components: {
AppSidebarNav,
},
setup() {
const store = useStore()
return {
logoNegative,
sygnet,
sidebarUnfoldable: computed(() => store.state.sidebarUnfoldable),
sidebarVisible: computed(() => store.state.sidebarVisible),
}
},
}
</script>

View file

@ -0,0 +1,141 @@
import { defineComponent, h, onMounted, ref, resolveComponent } from 'vue'
import { RouterLink, useRoute } from 'vue-router'
import {
CBadge,
CSidebarNav,
CNavItem,
CNavGroup,
CNavTitle,
} from '@coreui/vue'
import nav from '@/_nav.js'
const normalizePath = (path) =>
decodeURI(path)
.replace(/#.*$/, '')
.replace(/(index)?\.(html)$/, '')
const isActiveLink = (route, link) => {
if (link === undefined) {
return false
}
if (route.hash === link) {
return true
}
const currentPath = normalizePath(route.path)
const targetPath = normalizePath(link)
return currentPath === targetPath
}
const isActiveItem = (route, item) => {
if (isActiveLink(route, item.to)) {
return true
}
if (item.items) {
return item.items.some((child) => isActiveItem(route, child))
}
return false
}
const AppSidebarNav = defineComponent({
name: 'AppSidebarNav',
components: {
CNavItem,
CNavGroup,
CNavTitle,
},
setup() {
const route = useRoute()
const firstRender = ref(true)
onMounted(() => {
firstRender.value = false
})
const renderItem = (item) => {
if (item.items) {
return h(
CNavGroup,
{
...(firstRender.value && {
visible: item.items.some((child) => isActiveItem(route, child)),
}),
},
{
togglerContent: () => [
h(resolveComponent('CIcon'), {
customClassName: 'nav-icon',
name: item.icon,
}),
item.name,
],
default: () => item.items.map((child) => renderItem(child)),
},
)
}
return item.to
? h(
RouterLink,
{
to: item.to,
custom: true,
},
{
default: (props) =>
h(
resolveComponent(item.component),
{
active: props.isActive,
href: props.href,
onClick: () => props.navigate(),
},
{
default: () => [
item.icon &&
h(resolveComponent('CIcon'), {
customClassName: 'nav-icon',
name: item.icon,
}),
item.name,
item.badge &&
h(
CBadge,
{
class: 'ms-auto',
color: item.badge.color,
},
{
default: () => item.badge.text,
},
),
],
},
),
},
)
: h(
resolveComponent(item.component),
{},
{
default: () => item.name,
},
)
}
return () =>
h(
CSidebarNav,
{},
{
default: () => nav.map((item) => renderItem(item)),
},
)
},
})
export { AppSidebarNav }

View file

@ -0,0 +1,24 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
export class ApiError extends Error {
public readonly url: string;
public readonly status: number;
public readonly statusText: string;
public readonly body: any;
public readonly request: ApiRequestOptions;
constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
super(message);
this.name = 'ApiError';
this.url = response.url;
this.status = response.status;
this.statusText = response.statusText;
this.body = response.body;
this.request = request;
}
}

View file

@ -0,0 +1,16 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type ApiRequestOptions = {
readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
readonly url: string;
readonly path?: Record<string, any>;
readonly cookies?: Record<string, any>;
readonly headers?: Record<string, any>;
readonly query?: Record<string, any>;
readonly formData?: Record<string, any>;
readonly body?: any;
readonly mediaType?: string;
readonly responseHeader?: string;
readonly errors?: Record<number, string>;
};

View file

@ -0,0 +1,10 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type ApiResult = {
readonly url: string;
readonly ok: boolean;
readonly status: number;
readonly statusText: string;
readonly body: any;
};

View file

@ -0,0 +1,128 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export class CancelError extends Error {
constructor(message: string) {
super(message);
this.name = 'CancelError';
}
public get isCancelled(): boolean {
return true;
}
}
export interface OnCancel {
readonly isResolved: boolean;
readonly isRejected: boolean;
readonly isCancelled: boolean;
(cancelHandler: () => void): void;
}
export class CancelablePromise<T> implements Promise<T> {
readonly [Symbol.toStringTag]!: string;
private _isResolved: boolean;
private _isRejected: boolean;
private _isCancelled: boolean;
private readonly _cancelHandlers: (() => void)[];
private readonly _promise: Promise<T>;
private _resolve?: (value: T | PromiseLike<T>) => void;
private _reject?: (reason?: any) => void;
constructor(
executor: (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: any) => void,
onCancel: OnCancel
) => void
) {
this._isResolved = false;
this._isRejected = false;
this._isCancelled = false;
this._cancelHandlers = [];
this._promise = new Promise<T>((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
const onResolve = (value: T | PromiseLike<T>): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._isResolved = true;
this._resolve?.(value);
};
const onReject = (reason?: any): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._isRejected = true;
this._reject?.(reason);
};
const onCancel = (cancelHandler: () => void): void => {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._cancelHandlers.push(cancelHandler);
};
Object.defineProperty(onCancel, 'isResolved', {
get: (): boolean => this._isResolved,
});
Object.defineProperty(onCancel, 'isRejected', {
get: (): boolean => this._isRejected,
});
Object.defineProperty(onCancel, 'isCancelled', {
get: (): boolean => this._isCancelled,
});
return executor(onResolve, onReject, onCancel as OnCancel);
});
}
public then<TResult1 = T, TResult2 = never>(
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
): Promise<TResult1 | TResult2> {
return this._promise.then(onFulfilled, onRejected);
}
public catch<TResult = never>(
onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
): Promise<T | TResult> {
return this._promise.catch(onRejected);
}
public finally(onFinally?: (() => void) | null): Promise<T> {
return this._promise.finally(onFinally);
}
public cancel(): void {
if (this._isResolved || this._isRejected || this._isCancelled) {
return;
}
this._isCancelled = true;
if (this._cancelHandlers.length) {
try {
for (const cancelHandler of this._cancelHandlers) {
cancelHandler();
}
} catch (error) {
console.warn('Cancellation threw an error', error);
return;
}
}
this._cancelHandlers.length = 0;
this._reject?.(new CancelError('Request aborted'));
}
public get isCancelled(): boolean {
return this._isCancelled;
}
}

View file

@ -0,0 +1,31 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ApiRequestOptions } from './ApiRequestOptions';
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
type Headers = Record<string, string>;
export type OpenAPIConfig = {
BASE: string;
VERSION: string;
WITH_CREDENTIALS: boolean;
CREDENTIALS: 'include' | 'omit' | 'same-origin';
TOKEN?: string | Resolver<string>;
USERNAME?: string | Resolver<string>;
PASSWORD?: string | Resolver<string>;
HEADERS?: Headers | Resolver<Headers>;
ENCODE_PATH?: (path: string) => string;
};
export const OpenAPI: OpenAPIConfig = {
BASE: '',
VERSION: '0.0.1',
WITH_CREDENTIALS: false,
CREDENTIALS: 'include',
TOKEN: undefined,
USERNAME: undefined,
PASSWORD: undefined,
HEADERS: undefined,
ENCODE_PATH: undefined,
};

View file

@ -0,0 +1,304 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import axios from 'axios';
import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import FormData from 'form-data';
import { ApiError } from './ApiError';
import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import type { OpenAPIConfig } from './OpenAPI';
const isDefined = <T>(value: T | null | undefined): value is Exclude<T, null | undefined> => {
return value !== undefined && value !== null;
};
const isString = (value: any): value is string => {
return typeof value === 'string';
};
const isStringWithValue = (value: any): value is string => {
return isString(value) && value !== '';
};
const isBlob = (value: any): value is Blob => {
return (
typeof value === 'object' &&
typeof value.type === 'string' &&
typeof value.stream === 'function' &&
typeof value.arrayBuffer === 'function' &&
typeof value.constructor === 'function' &&
typeof value.constructor.name === 'string' &&
/^(Blob|File)$/.test(value.constructor.name) &&
/^(Blob|File)$/.test(value[Symbol.toStringTag])
);
};
const isFormData = (value: any): value is FormData => {
return value instanceof FormData;
};
const isSuccess = (status: number): boolean => {
return status >= 200 && status < 300;
};
const base64 = (str: string): string => {
try {
return btoa(str);
} catch (err) {
// @ts-ignore
return Buffer.from(str).toString('base64');
}
};
const getQueryString = (params: Record<string, any>): string => {
const qs: string[] = [];
const append = (key: string, value: any) => {
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
};
const process = (key: string, value: any) => {
if (isDefined(value)) {
if (Array.isArray(value)) {
value.forEach(v => {
process(key, v);
});
} else if (typeof value === 'object') {
Object.entries(value).forEach(([k, v]) => {
process(`${key}[${k}]`, v);
});
} else {
append(key, value);
}
}
};
Object.entries(params).forEach(([key, value]) => {
process(key, value);
});
if (qs.length > 0) {
return `?${qs.join('&')}`;
}
return '';
};
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
const encoder = config.ENCODE_PATH || encodeURI;
const path = options.url
.replace('{api-version}', config.VERSION)
.replace(/{(.*?)}/g, (substring: string, group: string) => {
if (options.path?.hasOwnProperty(group)) {
return encoder(String(options.path[group]));
}
return substring;
});
const url = `${config.BASE}${path}`;
if (options.query) {
return `${url}${getQueryString(options.query)}`;
}
return url;
};
const getFormData = (options: ApiRequestOptions): FormData | undefined => {
if (options.formData) {
const formData = new FormData();
const process = (key: string, value: any) => {
if (isString(value) || isBlob(value)) {
formData.append(key, value);
} else {
formData.append(key, JSON.stringify(value));
}
};
Object.entries(options.formData)
.filter(([_, value]) => isDefined(value))
.forEach(([key, value]) => {
if (Array.isArray(value)) {
value.forEach(v => process(key, v));
} else {
process(key, value);
}
});
return formData;
}
return undefined;
};
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
const resolve = async <T>(options: ApiRequestOptions, resolver?: T | Resolver<T>): Promise<T | undefined> => {
if (typeof resolver === 'function') {
return (resolver as Resolver<T>)(options);
}
return resolver;
};
const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions, formData?: FormData): Promise<Record<string, string>> => {
const token = await resolve(options, config.TOKEN);
const username = await resolve(options, config.USERNAME);
const password = await resolve(options, config.PASSWORD);
const additionalHeaders = await resolve(options, config.HEADERS);
const formHeaders = typeof formData?.getHeaders === 'function' && formData?.getHeaders() || {}
const headers = Object.entries({
Accept: 'application/json',
...additionalHeaders,
...options.headers,
...formHeaders,
})
.filter(([_, value]) => isDefined(value))
.reduce((headers, [key, value]) => ({
...headers,
[key]: String(value),
}), {} as Record<string, string>);
if (isStringWithValue(token)) {
headers['Authorization'] = `Bearer ${token}`;
}
if (isStringWithValue(username) && isStringWithValue(password)) {
const credentials = base64(`${username}:${password}`);
headers['Authorization'] = `Basic ${credentials}`;
}
if (options.body) {
if (options.mediaType) {
headers['Content-Type'] = options.mediaType;
} else if (isBlob(options.body)) {
headers['Content-Type'] = options.body.type || 'application/octet-stream';
} else if (isString(options.body)) {
headers['Content-Type'] = 'text/plain';
} else if (!isFormData(options.body)) {
headers['Content-Type'] = 'application/json';
}
}
return headers;
};
const getRequestBody = (options: ApiRequestOptions): any => {
if (options.body) {
return options.body;
}
return undefined;
};
const sendRequest = async <T>(
config: OpenAPIConfig,
options: ApiRequestOptions,
url: string,
body: any,
formData: FormData | undefined,
headers: Record<string, string>,
onCancel: OnCancel
): Promise<AxiosResponse<T>> => {
const source = axios.CancelToken.source();
const requestConfig: AxiosRequestConfig = {
url,
headers,
data: body ?? formData,
method: options.method,
withCredentials: config.WITH_CREDENTIALS,
cancelToken: source.token,
};
onCancel(() => source.cancel('The user aborted a request.'));
try {
return await axios.request(requestConfig);
} catch (error) {
const axiosError = error as AxiosError<T>;
if (axiosError.response) {
return axiosError.response;
}
throw error;
}
};
const getResponseHeader = (response: AxiosResponse<any>, responseHeader?: string): string | undefined => {
if (responseHeader) {
const content = response.headers[responseHeader];
if (isString(content)) {
return content;
}
}
return undefined;
};
const getResponseBody = (response: AxiosResponse<any>): any => {
if (response.status !== 204) {
return response.data;
}
return undefined;
};
const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => {
const errors: Record<number, string> = {
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
500: 'Internal Server Error',
502: 'Bad Gateway',
503: 'Service Unavailable',
...options.errors,
}
const error = errors[result.status];
if (error) {
throw new ApiError(options, result, error);
}
if (!result.ok) {
throw new ApiError(options, result, 'Generic Error');
}
};
/**
* Request method
* @param config The OpenAPI configuration object
* @param options The request options from the service
* @returns CancelablePromise<T>
* @throws ApiError
*/
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(config, options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(config, options, formData);
if (!onCancel.isCancelled) {
const response = await sendRequest<T>(config, options, url, body, formData, headers, onCancel);
const responseBody = getResponseBody(response);
const responseHeader = getResponseHeader(response, options.responseHeader);
const result: ApiResult = {
url,
ok: isSuccess(response.status),
status: response.status,
statusText: response.statusText,
body: responseHeader ?? responseBody,
};
catchErrorCodes(options, result);
resolve(result.body);
}
} catch (error) {
reject(error);
}
});
};

View file

@ -0,0 +1,37 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export { ApiError } from './core/ApiError';
export { CancelablePromise, CancelError } from './core/CancelablePromise';
export { OpenAPI } from './core/OpenAPI';
export type { OpenAPIConfig } from './core/OpenAPI';
export { App } from './models/App';
export { App2 } from './models/App2';
export { AppDetails } from './models/AppDetails';
export type { AppList } from './models/AppList';
export type { CheckerResult } from './models/CheckerResult';
export type { ErrorModel } from './models/ErrorModel';
export type { FEConfig } from './models/FEConfig';
export type { MessageResult } from './models/MessageResult';
export type { post_message_request } from './models/post_message_request';
export type { stringList } from './models/stringList';
export type { TransportConfig } from './models/TransportConfig';
export type { User } from './models/User';
export type { UserList } from './models/UserList';
export { $App } from './schemas/$App';
export { $App2 } from './schemas/$App2';
export { $AppDetails } from './schemas/$AppDetails';
export { $AppList } from './schemas/$AppList';
export { $CheckerResult } from './schemas/$CheckerResult';
export { $ErrorModel } from './schemas/$ErrorModel';
export { $FEConfig } from './schemas/$FEConfig';
export { $MessageResult } from './schemas/$MessageResult';
export { $post_message_request } from './schemas/$post_message_request';
export { $stringList } from './schemas/$stringList';
export { $TransportConfig } from './schemas/$TransportConfig';
export { $User } from './schemas/$User';
export { $UserList } from './schemas/$UserList';
export { DefaultService } from './services/DefaultService';

View file

@ -0,0 +1,80 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type App = {
/**
* Application Name
*/
appname: string;
associatedusers: Array<{
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
email: string;
firstname: string;
id: number;
lastname: string;
transports?: Array<{
config: string;
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
id: number;
transport: string;
updatedat: string;
}>;
updatedat: string;
}>;
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
/**
* Description of Application
*/
description: string;
filters: Array<{
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
id: number;
name: string;
updatedat: string;
}>;
/**
* Icon of Application
*/
icon: string;
id: number;
/**
* Status of Application
*/
status: App.status;
updatedat: string;
/**
* URL of Application
*/
url: string;
};
export namespace App {
/**
* Status of Application
*/
export enum status {
ENABLED = 'Enabled',
DISABLED = 'Disabled',
}
}

View file

@ -0,0 +1,84 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type App2 = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
/**
* Application Name
*/
appname: string;
associatedusers: Array<{
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
email: string;
firstname: string;
id: number;
lastname: string;
transports?: Array<{
config: string;
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
id: number;
transport: string;
updatedat: string;
}>;
updatedat: string;
}>;
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
/**
* Description of Application
*/
description: string;
filters: Array<{
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
id: number;
name: string;
updatedat: string;
}>;
/**
* Icon of Application
*/
icon: string;
id: number;
/**
* Status of Application
*/
status: App2.status;
updatedat: string;
/**
* URL of Application
*/
url: string;
};
export namespace App2 {
/**
* Status of Application
*/
export enum status {
ENABLED = 'Enabled',
DISABLED = 'Disabled',
}
}

View file

@ -0,0 +1,44 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type AppDetails = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
/**
* Application Name
*/
appname: string;
/**
* Description of Application
*/
description: string;
/**
* Icon of Application
*/
icon: string;
/**
* Status of Application
*/
status: AppDetails.status;
/**
* URL of Application
*/
url: string;
};
export namespace AppDetails {
/**
* Status of Application
*/
export enum status {
ENABLED = 'Enabled',
DISABLED = 'Disabled',
}
}

View file

@ -0,0 +1,7 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { App } from './App';
export type AppList = Array<App>;

View file

@ -0,0 +1,17 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type CheckerResult = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
details?: Record<string, {
error?: string;
status: string;
timestamp?: string;
}>;
status: string;
};

View file

@ -0,0 +1,48 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type ErrorModel = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
/**
* A human-readable explanation specific to this occurrence of the problem.
*/
detail?: string;
/**
* Optional list of individual error details
*/
errors?: Array<{
/**
* Where the error occured, e.g. 'body.items[3].tags' or 'path.thing-id'
*/
location?: string;
/**
* Error message text
*/
message?: string;
/**
* The value at the given location
*/
value?: any;
}>;
/**
* A URI reference that identifies the specific occurence of the problem.
*/
instance?: string;
/**
* HTTP status code
*/
status?: number;
/**
* A short, human-readable summary of the problem type. This value should not change between occurances of the error.
*/
title?: string;
/**
* A URI reference to human-readable documentation for the error.
*/
type?: string;
};

View file

@ -0,0 +1,20 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type FEConfig = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
/**
* Provider OAuth Config for Frontend
*/
oauthproviders: Record<string, {
/**
* OAuth Client ID
*/
clientid: string;
}>;
};

View file

@ -0,0 +1,19 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type MessageResult = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
/**
* Message ID
*/
message_id: number;
/**
* Status of Message
*/
status: string;
};

View file

@ -0,0 +1,20 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type TransportConfig = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
config: string;
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
id: number;
transport: string;
updatedat: string;
};

View file

@ -0,0 +1,28 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type User = {
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
email: string;
firstname: string;
id: number;
lastname: string;
transports?: Array<{
config: string;
createdat: string;
deletedat: {
time: string;
valid: boolean;
};
id: number;
transport: string;
updatedat: string;
}>;
updatedat: string;
};

View file

@ -0,0 +1,7 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { User } from './User';
export type UserList = Array<User>;

View file

@ -0,0 +1,35 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type post_message_request = {
/**
* An optional URL to a JSON Schema document describing this resource
*/
$schema?: string;
/**
* Additional Fields
*/
fields?: Record<string, any>;
/**
* Message to be Sent
*/
message: string;
/**
* Severity of Message
*/
severity?: string;
/**
* Short Message to be Sent
*/
shortmessage?: string;
/**
* Timestamp of Message
*/
timestamp?: string;
/**
* Topic of Message
*/
topic?: string;
};

View file

@ -0,0 +1,6 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type stringList = Array<string>;

View file

@ -0,0 +1,195 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export const $App = {
properties: {
appname: {
type: 'string',
description: `Application Name`,
isRequired: true,
pattern: '^[a-z0-9]+$',
},
associatedusers: {
type: 'array',
contains: {
properties: {
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
email: {
type: 'string',
isRequired: true,
},
firstname: {
type: 'string',
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
lastname: {
type: 'string',
isRequired: true,
},
transports: {
type: 'array',
contains: {
properties: {
config: {
type: 'string',
isRequired: true,
},
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
transport: {
type: 'string',
isRequired: true,
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
},
},
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
},
},
isRequired: true,
},
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
description: {
type: 'string',
description: `Description of Application`,
isRequired: true,
},
filters: {
type: 'array',
contains: {
properties: {
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
name: {
type: 'string',
isRequired: true,
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
},
},
isRequired: true,
},
icon: {
type: 'string',
description: `Icon of Application`,
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
status: {
type: 'Enum',
isRequired: true,
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
url: {
type: 'string',
description: `URL of Application`,
isRequired: true,
},
},
} as const;

View file

@ -0,0 +1,200 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export const $App2 = {
properties: {
$schema: {
type: 'string',
description: `An optional URL to a JSON Schema document describing this resource`,
format: 'uri',
},
appname: {
type: 'string',
description: `Application Name`,
isRequired: true,
pattern: '^[a-z0-9]+$',
},
associatedusers: {
type: 'array',
contains: {
properties: {
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
email: {
type: 'string',
isRequired: true,
},
firstname: {
type: 'string',
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
lastname: {
type: 'string',
isRequired: true,
},
transports: {
type: 'array',
contains: {
properties: {
config: {
type: 'string',
isRequired: true,
},
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
transport: {
type: 'string',
isRequired: true,
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
},
},
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
},
},
isRequired: true,
},
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
description: {
type: 'string',
description: `Description of Application`,
isRequired: true,
},
filters: {
type: 'array',
contains: {
properties: {
createdat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
deletedat: {
properties: {
time: {
type: 'string',
isRequired: true,
format: 'date-time',
},
valid: {
type: 'boolean',
isRequired: true,
},
},
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
name: {
type: 'string',
isRequired: true,
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
},
},
isRequired: true,
},
icon: {
type: 'string',
description: `Icon of Application`,
isRequired: true,
},
id: {
type: 'number',
isRequired: true,
format: 'int32',
},
status: {
type: 'Enum',
isRequired: true,
},
updatedat: {
type: 'string',
isRequired: true,
format: 'date-time',
},
url: {
type: 'string',
description: `URL of Application`,
isRequired: true,
},
},
} as const;

Some files were not shown because too many files have changed in this diff Show more