Refactor folder names
1
bitchmin-api/.virtualenv
Normal file
@@ -0,0 +1 @@
|
||||
BitchMin
|
||||
@@ -26,6 +26,7 @@ CELERY_TASK_LIST = [
|
||||
]
|
||||
import flask_monitoringdashboard as dashboard
|
||||
|
||||
|
||||
def create_app(app_name='bitchmin', config_class=Config):
|
||||
logger.info('Creating app {}'.format(app_name))
|
||||
app = Flask(app_name)
|
||||
@@ -64,6 +64,11 @@ def check_host_record():
|
||||
host = args['host']
|
||||
|
||||
actual_ip_records = get_dns_records(host, ip, os.getenv('DNS_SERVER'))
|
||||
if len(actual_ip_records) == 0:
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'payload': 'Host {} is in not found in {}'.format(host, os.getenv('DNS_SERVER'), ip)
|
||||
}), 200
|
||||
|
||||
if ip in actual_ip_records:
|
||||
return jsonify({
|
||||
@@ -13,7 +13,8 @@ class Config(object):
|
||||
ISDEV = ISDEV
|
||||
SECRET_KEY = os.getenv('SECRET_KEY') or 'you-will-never-guess'
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
|
||||
'sqlite:///' + os.path.join(basedir, '../app.db')
|
||||
'postgresql+psycopg2://bitchmin:bitchmin@localhost/bitchmin'
|
||||
# 'sqlite:///' + os.path.join(basedir, '../app.db')
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
LOG_TO_STDOUT = os.getenv('LOG_TO_STDOUT')
|
||||
ADMINS = ['Ferg@lMoran.me']
|
||||
@@ -8,7 +8,7 @@ sqlalchemy_utils
|
||||
phue
|
||||
python-dotenv
|
||||
PyJWT
|
||||
psycopg2-binary==2.8.5
|
||||
psycopg2-binary==2.8.6
|
||||
Psycopg2
|
||||
pylint
|
||||
werkzeug
|
||||
@@ -8,7 +8,6 @@ module.exports = {
|
||||
extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/typescript/recommended'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
project: ['./tsconfig.json', './tsconfig.eslint.json'],
|
||||
},
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
5
bitchmin-client/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
20
bitchmin-client/src/api/config.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as qs from 'qs';
|
||||
|
||||
export const API_BASE = process.env.VUE_APP_API_SERVER;
|
||||
|
||||
export const apiConfig = {
|
||||
returnRejectedPromiseOnError: true,
|
||||
withCredentials: true,
|
||||
credentials: 'same-origin',
|
||||
timeout: 30000,
|
||||
baseURL: API_BASE,
|
||||
headers: {
|
||||
common: {
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
Pragma: 'no-cache',
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
},
|
||||
paramsSerializer: (params: any) => qs.stringify(params, { indices: false }),
|
||||
};
|
||||
80
bitchmin-client/src/api/dnsApi.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { Api } from '@/api/apiBase';
|
||||
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import { apiConfig } from '@/api/config';
|
||||
import { ApiResult, DataApiResult } from '@/api/apiResult';
|
||||
import { DnsRecord } from '@/models/dnsRecord';
|
||||
|
||||
export class DnsApi extends Api {
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
// NEVER FORGET THE SUPER
|
||||
super(config);
|
||||
}
|
||||
|
||||
public async updateDnsRecord(
|
||||
hostName: string,
|
||||
ipAddress: string,
|
||||
): Promise<DataApiResult<DnsRecord>> {
|
||||
const result = await this.post<
|
||||
ApiResult,
|
||||
any,
|
||||
AxiosResponse<DataApiResult<DnsRecord>>
|
||||
>('/dns/', {
|
||||
host: hostName,
|
||||
ip: ipAddress,
|
||||
});
|
||||
return result.data;
|
||||
}
|
||||
|
||||
public async deleteDnsRecord(
|
||||
hostName: string,
|
||||
): Promise<number> {
|
||||
const result = await this.delete(`/dns/?host=${hostName}`);
|
||||
return result.status;
|
||||
}
|
||||
|
||||
public async refreshDnsRecord(
|
||||
hostName: string,
|
||||
ip: string,
|
||||
): Promise<DataApiResult<DnsRecord>> {
|
||||
const result = await this.post<
|
||||
ApiResult,
|
||||
any,
|
||||
AxiosResponse<DataApiResult<DnsRecord>>
|
||||
>('/dns/refresh', {
|
||||
host: hostName,
|
||||
ip,
|
||||
});
|
||||
return result.data;
|
||||
}
|
||||
|
||||
public async verifyDnsRecord(
|
||||
hostName: string,
|
||||
ip: string,
|
||||
): Promise<DataApiResult<string>> {
|
||||
const result = await this.post<
|
||||
ApiResult,
|
||||
any,
|
||||
AxiosResponse<DataApiResult<string>>
|
||||
>('/dns/check/', {
|
||||
host: hostName,
|
||||
ip,
|
||||
});
|
||||
return result.data;
|
||||
}
|
||||
|
||||
public async getDnsRecords(): Promise<DnsRecord[]> {
|
||||
const result = await this.get<DnsRecord[]>('/dns/list');
|
||||
return result.data;
|
||||
}
|
||||
|
||||
public async getMyIP(): Promise<string> {
|
||||
const result = await this.get<DataApiResult<string>>('/dns/myip');
|
||||
return result.data.payload || 'Unknown IP';
|
||||
}
|
||||
|
||||
public async getHeaders(): Promise<any> {
|
||||
const result = await this.get<DataApiResult<any>>('/dns/headers');
|
||||
return result.data.payload;
|
||||
}
|
||||
}
|
||||
export const dnsApi = new DnsApi(apiConfig);
|
||||
51
bitchmin-client/src/api/lightsApi.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
|
||||
import { Api } from '@/api/apiBase';
|
||||
|
||||
import { apiConfig } from '@/api/config';
|
||||
import { Light } from '@/models';
|
||||
import { ApiResult, DataApiResult } from './apiResult';
|
||||
|
||||
export class LightsApi extends Api {
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
// NEVER FORGET THE SUPER
|
||||
super(config);
|
||||
}
|
||||
|
||||
async getLights(): Promise<Light[]> {
|
||||
const lights = await this.get<DataApiResult<Light[]>>(
|
||||
'/lights/getlights',
|
||||
);
|
||||
return lights.data.payload || [];
|
||||
}
|
||||
|
||||
async changeBrightness(
|
||||
lightId: number,
|
||||
brightness: number,
|
||||
): Promise<boolean> {
|
||||
const result = await this.post<
|
||||
ApiResult,
|
||||
any,
|
||||
AxiosResponse<ApiResult>
|
||||
>('/lights/setbrightness', {
|
||||
lightId,
|
||||
brightness,
|
||||
});
|
||||
return result.data.status === 'success';
|
||||
}
|
||||
|
||||
async changeColour(
|
||||
lightId: number,
|
||||
colour: string,
|
||||
): Promise<boolean> {
|
||||
const result = await this.post<
|
||||
ApiResult,
|
||||
any,
|
||||
AxiosResponse<ApiResult>
|
||||
>('/lights/changecolour', {
|
||||
lightId,
|
||||
rgbColour: colour,
|
||||
});
|
||||
return result.data.status === 'success';
|
||||
}
|
||||
}
|
||||
export const lightsApi = new LightsApi(apiConfig);
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 539 B |
@@ -58,6 +58,7 @@ export default class DnsUpdateForm extends Vue {
|
||||
ipAddressRules = [
|
||||
(v: string) => !!v || 'IP address is required',
|
||||
(v: string) =>
|
||||
// eslint-disable-next-line max-len
|
||||
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(
|
||||
v
|
||||
) || 'Invalid IP Address',
|
||||
47
bitchmin-client/src/components/Media/VideoTest.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div id="container">
|
||||
<video id="video" width="640" height="480" autoplay></video>
|
||||
<button id="snap"></button>
|
||||
<canvas id="canvas" width="640" height="480"></canvas>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
@Component({
|
||||
components: {},
|
||||
})
|
||||
export default class VideoTest extends Vue {
|
||||
async mounted() {
|
||||
console.log('VideoTest', 'mounted');
|
||||
const video = document.getElementById('video') as HTMLVideoElement;
|
||||
if (video !== null) {
|
||||
if (navigator.mediaDevices.getUserMedia) {
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true })
|
||||
.then(function (stream) {
|
||||
video.srcObject = stream;
|
||||
})
|
||||
.catch(function (err0r) {
|
||||
console.log('Something went wrong!');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped=true>
|
||||
#container {
|
||||
margin: 0px auto;
|
||||
width: 500px;
|
||||
height: 375px;
|
||||
border: 10px #333 solid;
|
||||
}
|
||||
#videoElement {
|
||||
width: 500px;
|
||||
height: 375px;
|
||||
background-color: #666;
|
||||
}
|
||||
</style>
|
||||
32
bitchmin-client/src/registerServiceWorker.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from 'register-service-worker';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
'App is being served from cache by a service worker.\n'
|
||||
+ 'For more details, visit https://goo.gl/AFskqB',
|
||||
);
|
||||
},
|
||||
registered() {
|
||||
console.log('Service worker has been registered.');
|
||||
},
|
||||
cached() {
|
||||
console.log('Content has been cached for offline use.');
|
||||
},
|
||||
updatefound() {
|
||||
console.log('New content is downloading.');
|
||||
},
|
||||
updated() {
|
||||
console.log('New content is available; please refresh.');
|
||||
},
|
||||
offline() {
|
||||
console.log('No internet connection found. App is running in offline mode.');
|
||||
},
|
||||
error(error) {
|
||||
console.error('Error during service worker registration:', error);
|
||||
},
|
||||
});
|
||||
}
|
||||
107
bitchmin-client/src/router/index.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import Vue from 'vue';
|
||||
import VueRouter, { RouteConfig } from 'vue-router';
|
||||
import store from '@/store';
|
||||
import Home from '../views/Home.vue';
|
||||
import Login from '../views/Login.vue';
|
||||
import Lights from '../views/Lights.vue';
|
||||
import About from '../views/About.vue';
|
||||
import Debug from '../views/Debug.vue';
|
||||
import BitchNS from '../views/BitchNS.vue';
|
||||
import JwtDecoder from '../views/JwtDecoder.vue';
|
||||
import MyIp from '../views/MyIp.vue';
|
||||
import Media from '../views/Media.vue';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Home,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: Login,
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/media',
|
||||
name: 'Media',
|
||||
component: Media,
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/bitchns',
|
||||
name: 'BitchNS',
|
||||
component: BitchNS,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/jwt',
|
||||
name: 'JwtDecoder',
|
||||
component: JwtDecoder,
|
||||
|
||||
},
|
||||
{
|
||||
path: '/myip',
|
||||
name: 'MyIP',
|
||||
component: MyIp,
|
||||
},
|
||||
{
|
||||
path: '/debug',
|
||||
name: 'Debug',
|
||||
component: Debug,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/lights',
|
||||
name: 'Lights',
|
||||
component: Lights,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'About',
|
||||
component: About,
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
// abstract: true,
|
||||
mode: 'history',
|
||||
routes,
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.name === 'Home') {
|
||||
console.log('index', 'Home Route Called', store.getters.isLoggedIn);
|
||||
}
|
||||
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
||||
if (store.getters.isLoggedIn) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
next('/login');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||