🪄 Adds api service with updates
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
import { user } from '$lib/stores/user';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
import { Err, Ok, type Result } from './utilities';
|
||||||
|
|
||||||
|
export namespace api {
|
||||||
|
export function get<TResponse>(endpoint: string, params?: RequestInit) {
|
||||||
|
return sendRequest<TResponse>(endpoint, 'GET', null, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function post<TResponse>(endpoint: string, data?: unknown) {
|
||||||
|
return sendRequest<TResponse>(endpoint, 'POST', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function put<TResponse>(endpoint: string, data?: unknown) {
|
||||||
|
return sendRequest<TResponse>(endpoint, 'PUT', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remove<TResponse>(endpoint: string) {
|
||||||
|
return sendRequest<TResponse>(endpoint, 'DELETE');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendRequest<TResponse>(
|
||||||
|
endpoint: string,
|
||||||
|
method: string,
|
||||||
|
data?: unknown,
|
||||||
|
params?: RequestInit
|
||||||
|
): Promise<Result<TResponse, Error>> {
|
||||||
|
const user_token = get(user).bearer_token;
|
||||||
|
const body = data !== null && typeof data !== 'undefined' ? JSON.stringify(data) : undefined;
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
...params,
|
||||||
|
method,
|
||||||
|
body,
|
||||||
|
headers: {
|
||||||
|
...params?.headers,
|
||||||
|
Authorization: user_token ? 'Bearer ' + user_token : 'Basic',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await fetch(endpoint, request);
|
||||||
|
} catch (error) {
|
||||||
|
return Err.new(new Error(), 'An error has occurred');
|
||||||
|
}
|
||||||
|
|
||||||
|
const isResponseOk = response.status >= 200 && response.status < 400;
|
||||||
|
if (!isResponseOk) {
|
||||||
|
if (response.status === 401) {
|
||||||
|
return Err.new(new ApiError(response), 'User was not authorized');
|
||||||
|
}
|
||||||
|
return Err.new(new ApiError(response), 'An error has occurred');
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = response.headers.get('Content-Type') ?? response.headers.get('Content-Type');
|
||||||
|
if (contentType && contentType.includes('application/json')) {
|
||||||
|
const data = await response.json();
|
||||||
|
return Ok.new(data as TResponse);
|
||||||
|
} else {
|
||||||
|
// Handle empty object as response
|
||||||
|
return Ok.new(null as TResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ApiError extends Error {
|
||||||
|
constructor(public readonly response: Response) {
|
||||||
|
super(`${response.status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
import GithubUpdateDialog from '$lib/components/GithubUpdateDialog.svelte';
|
import GithubUpdateDialog from '$lib/components/GithubUpdateDialog.svelte';
|
||||||
import { compareVersions } from 'compare-versions';
|
import { compareVersions } from 'compare-versions';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
import type { GithubRelease } from '$lib/models';
|
||||||
|
|
||||||
export let update = false;
|
export let update = false;
|
||||||
|
|
||||||
@@ -17,67 +19,55 @@
|
|||||||
let firmwareDownloadLink: string;
|
let firmwareDownloadLink: string;
|
||||||
|
|
||||||
async function getGithubAPI() {
|
async function getGithubAPI() {
|
||||||
try {
|
const headers = {
|
||||||
const response = await fetch(
|
accept: 'application/vnd.github+json',
|
||||||
'https://api.github.com/repos/' + $page.data.github + '/releases/latest',
|
'X-GitHub-Api-Version': '2022-11-28'
|
||||||
{
|
}
|
||||||
method: 'GET',
|
const result = await api.get<GithubRelease>(`https://api.github.com/repos/${$page.data.github}/releases/latest`, {headers})
|
||||||
headers: {
|
if (result.inner.message === "404" || result.inner.message == "Not Found") {
|
||||||
accept: 'application/vnd.github+json',
|
console.warn('Error: Could not find releases in the repository');
|
||||||
'X-GitHub-Api-Version': '2022-11-28'
|
return
|
||||||
}
|
}
|
||||||
}
|
if (result.isErr()) {
|
||||||
);
|
console.error('Error:', result.inner);
|
||||||
const results = await response.json();
|
return
|
||||||
if (results.message == "Not Found") {
|
}
|
||||||
console.error('Error: Could not find releases in the repository');
|
|
||||||
return;
|
const results = result.inner;
|
||||||
|
update = false;
|
||||||
|
firmwareVersion = '';
|
||||||
|
|
||||||
|
if (compareVersions(results.tag_name, $page.data.features.firmware_version) === 1) {
|
||||||
|
// iterate over assets and find the correct one
|
||||||
|
for (let i = 0; i < results.assets.length; i++) {
|
||||||
|
// check if the asset is of type *.bin
|
||||||
|
if (
|
||||||
|
results.assets[i].name.includes('.bin') &&
|
||||||
|
results.assets[i].name.includes($page.data.features.firmware_built_target)
|
||||||
|
) {
|
||||||
|
update = true;
|
||||||
|
firmwareVersion = results.tag_name;
|
||||||
|
firmwareDownloadLink = results.assets[i].browser_download_url;
|
||||||
|
notifications.info('Firmware update available.', 5000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
update = false;
|
|
||||||
firmwareVersion = '';
|
|
||||||
|
|
||||||
if (compareVersions(results.tag_name, $page.data.features.firmware_version) === 1) {
|
|
||||||
// iterate over assets and find the correct one
|
|
||||||
for (let i = 0; i < results.assets.length; i++) {
|
|
||||||
// check if the asset is of type *.bin
|
|
||||||
if (
|
|
||||||
results.assets[i].name.includes('.bin') &&
|
|
||||||
results.assets[i].name.includes($page.data.features.firmware_built_target)
|
|
||||||
) {
|
|
||||||
update = true;
|
|
||||||
firmwareVersion = results.tag_name;
|
|
||||||
firmwareDownloadLink = results.assets[i].browser_download_url;
|
|
||||||
notifications.info('Firmware update available.', 5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postGithubDownload(url: string) {
|
async function postGithubDownload(url: string) {
|
||||||
try {
|
const result = await api.post('/api/downloadUpdate', { download_url: url });
|
||||||
const apiResponse = await fetch('/api/downloadUpdate', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ download_url: url })
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
if ($page.data.features.download_firmware && (!$page.data.features.security || $user.admin)) {
|
if ($page.data.features.download_firmware && (!$page.data.features.security || $user.admin)) {
|
||||||
getGithubAPI();
|
await getGithubAPI();
|
||||||
const interval = setInterval(
|
const interval = setInterval(
|
||||||
async () => {
|
async () => {
|
||||||
getGithubAPI();
|
await getGithubAPI();
|
||||||
},
|
},
|
||||||
60 * 60 * 1000
|
60 * 60 * 1000
|
||||||
); // once per hour
|
); // once per hour
|
||||||
|
|||||||
+16
-1
@@ -7,6 +7,17 @@ export interface ControllerInput {
|
|||||||
speed: number;
|
speed: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GithubRelease = {
|
||||||
|
message: string;
|
||||||
|
tag_name: string;
|
||||||
|
assets: Array<{
|
||||||
|
name: string;
|
||||||
|
browser_download_url: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type JWT = { access_token: string };
|
||||||
|
|
||||||
export type angles = number[] | Int16Array;
|
export type angles = number[] | Int16Array;
|
||||||
|
|
||||||
export type WifiStatus = {
|
export type WifiStatus = {
|
||||||
@@ -26,7 +37,11 @@ export type WifiStatus = {
|
|||||||
export type WifiSettings = {
|
export type WifiSettings = {
|
||||||
hostname: string;
|
hostname: string;
|
||||||
priority_RSSI: boolean;
|
priority_RSSI: boolean;
|
||||||
wifi_networks: networkItem[];
|
wifi_networks: NetworkItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NetworkList = {
|
||||||
|
networks: NetworkItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type KnownNetworkItem = {
|
export type KnownNetworkItem = {
|
||||||
|
|||||||
@@ -7,3 +7,30 @@ export const humanFileSize = (size: number): string => {
|
|||||||
export const capitalize = (str: string): string => {
|
export const capitalize = (str: string): string => {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const convertSeconds = (seconds: number) => {
|
||||||
|
// Calculate the number of seconds, minutes, hours, and days
|
||||||
|
let minutes = Math.floor(seconds / 60);
|
||||||
|
let hours = Math.floor(minutes / 60);
|
||||||
|
let days = Math.floor(hours / 24);
|
||||||
|
|
||||||
|
// Calculate the remaining hours, minutes, and seconds
|
||||||
|
hours = hours % 24;
|
||||||
|
minutes = minutes % 60;
|
||||||
|
seconds = seconds % 60;
|
||||||
|
|
||||||
|
// Create the formatted string
|
||||||
|
let result = '';
|
||||||
|
if (days > 0) {
|
||||||
|
result += days + ' day' + (days > 1 ? 's' : '') + ' ';
|
||||||
|
}
|
||||||
|
if (hours > 0) {
|
||||||
|
result += hours + ' hour' + (hours > 1 ? 's' : '') + ' ';
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
result += minutes + ' minute' + (minutes > 1 ? 's' : '') + ' ';
|
||||||
|
}
|
||||||
|
result += seconds + ' second' + (seconds > 1 ? 's' : '');
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
import Login from './login.svelte';
|
import Login from './login.svelte';
|
||||||
import { ModesEnum, mode, outControllerData, servoAngles, servoAnglesOut, socket } from '$lib/stores';
|
import { ModesEnum, mode, outControllerData, servoAngles, servoAnglesOut, socket } from '$lib/stores';
|
||||||
import type { Analytics, Battery, DownloadOTA } from '$lib/types/models';
|
import type { Analytics, Battery, DownloadOTA } from '$lib/types/models';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if ($user.bearer_token !== '') {
|
if ($user.bearer_token !== '') {
|
||||||
@@ -64,20 +65,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function validateUser(userdata: userProfile) {
|
async function validateUser(userdata: userProfile) {
|
||||||
try {
|
const result = await api.get('/api/verifyAuthorization')
|
||||||
const response = await fetch('/api/verifyAuthorization', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
user.invalidate();
|
||||||
headers: {
|
console.error('Error:', result.inner);
|
||||||
Authorization: 'Bearer ' + userdata.bearer_token,
|
}
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (response.status !== 200) {
|
|
||||||
user.invalidate();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import MQTT from '~icons/tabler/topology-star-3';
|
import MQTT from '~icons/tabler/topology-star-3';
|
||||||
import Client from '~icons/tabler/robot';
|
import Client from '~icons/tabler/robot';
|
||||||
import type { MQTTSettings, MQTTStatus } from '$lib/models';
|
import type { MQTTSettings, MQTTStatus } from '$lib/models';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
let mqttSettings: MQTTSettings;
|
let mqttSettings: MQTTSettings;
|
||||||
let mqttStatus: MQTTStatus;
|
let mqttStatus: MQTTStatus;
|
||||||
@@ -19,34 +20,22 @@
|
|||||||
let formField: any;
|
let formField: any;
|
||||||
|
|
||||||
async function getMQTTStatus() {
|
async function getMQTTStatus() {
|
||||||
try {
|
const result = await api.get<MQTTStatus>('/api/mqttStatus');
|
||||||
const response = await fetch('/api/mqttStatus', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
mqttStatus = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
mqttStatus = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return mqttStatus;
|
return mqttStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMQTTSettings() {
|
async function getMQTTSettings() {
|
||||||
try {
|
const result = await api.get<MQTTSettings>('/api/mqttSettings');
|
||||||
const response = await fetch('/api/mqttSettings', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
mqttSettings = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
mqttSettings = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return mqttSettings;
|
return mqttSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,25 +59,15 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function postMQTTSettings(data: MQTTSettings) {
|
async function postMQTTSettings(data: MQTTSettings) {
|
||||||
try {
|
const result = await api.post<MQTTSettings>('/api/mqttSettings', data);
|
||||||
const response = await fetch('/api/mqttSettings', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
notifications.error('User not authorized.', 3000);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
},
|
notifications.success('MQTT settings updated.', 3000);
|
||||||
body: JSON.stringify(data)
|
mqttSettings = result.inner
|
||||||
});
|
return mqttSettings;
|
||||||
if (response.status == 200) {
|
|
||||||
notifications.success('MQTT settings updated.', 3000);
|
|
||||||
mqttSettings = await response.json();
|
|
||||||
} else {
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmitMQTT() {
|
function handleSubmitMQTT() {
|
||||||
|
|||||||
@@ -2,32 +2,24 @@
|
|||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import { cubicOut } from 'svelte/easing';
|
import { cubicOut } from 'svelte/easing';
|
||||||
import SettingsCard from '$lib/components/SettingsCard.svelte';
|
import SettingsCard from '$lib/components/SettingsCard.svelte';
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { notifications } from '$lib/components/toasts/notifications';
|
import { notifications } from '$lib/components/toasts/notifications';
|
||||||
import Spinner from '$lib/components/Spinner.svelte';
|
import Spinner from '$lib/components/Spinner.svelte';
|
||||||
import MQTT from '~icons/tabler/topology-star-3';
|
import MQTT from '~icons/tabler/topology-star-3';
|
||||||
import Info from '~icons/tabler/info-circle';
|
import Info from '~icons/tabler/info-circle';
|
||||||
import type { BrokerSettings } from '$lib/types/models';
|
import type { BrokerSettings } from '$lib/types/models';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
let brokerSettings: BrokerSettings;
|
let brokerSettings: BrokerSettings;
|
||||||
|
|
||||||
let formField: any;
|
let formField: any;
|
||||||
|
|
||||||
async function getBrokerSettings() {
|
async function getBrokerSettings() {
|
||||||
try {
|
const result = await api.get<BrokerSettings>('/api/brokerSettings');
|
||||||
const response = await fetch('/api/brokerSettings', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
brokerSettings = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
brokerSettings = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let formErrors = {
|
let formErrors = {
|
||||||
@@ -37,25 +29,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function postBrokerSettings() {
|
async function postBrokerSettings() {
|
||||||
try {
|
const result = await api.post<BrokerSettings>('/api/brokerSettings', brokerSettings);
|
||||||
const response = await fetch('/api/brokerSettings', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
notifications.error('User not authorized.', 3000);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
},
|
notifications.success('Broker settings updated.', 3000);
|
||||||
body: JSON.stringify(brokerSettings)
|
brokerSettings = result.inner
|
||||||
});
|
|
||||||
if (response.status == 200) {
|
|
||||||
notifications.success('Broker settings updated.', 3000);
|
|
||||||
brokerSettings = await response.json();
|
|
||||||
} else {
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmitBroker() {
|
function handleSubmitBroker() {
|
||||||
|
|||||||
@@ -15,40 +15,27 @@
|
|||||||
import UTC from '~icons/tabler/clock-pin';
|
import UTC from '~icons/tabler/clock-pin';
|
||||||
import Stopwatch from '~icons/tabler/24-hours';
|
import Stopwatch from '~icons/tabler/24-hours';
|
||||||
import type { NTPSettings, NTPStatus } from '$lib/types/models';
|
import type { NTPSettings, NTPStatus } from '$lib/types/models';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
let ntpSettings: NTPSettings;
|
let ntpSettings: NTPSettings;
|
||||||
let ntpStatus: NTPStatus;
|
let ntpStatus: NTPStatus;
|
||||||
|
|
||||||
async function getNTPStatus() {
|
async function getNTPStatus() {
|
||||||
try {
|
const result = await api.get<NTPStatus>('/api/ntpStatus');
|
||||||
const response = await fetch('/api/ntpStatus', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
ntpStatus = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
ntpStatus = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getNTPSettings() {
|
async function getNTPSettings() {
|
||||||
try {
|
const result = await api.get<NTPSettings>('/api/ntpSettings');
|
||||||
const response = await fetch('/api/ntpSettings', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
ntpSettings = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
ntpSettings = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
@@ -70,25 +57,13 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function postNTPSettings(data: NTPSettings) {
|
async function postNTPSettings(data: NTPSettings) {
|
||||||
try {
|
const result = await api.post<NTPSettings>('/api/ntpSettings', data);
|
||||||
const response = await fetch('/api/ntpSettings', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
notifications.error('User not authorized.', 3000);
|
||||||
headers: {
|
console.error('Error:', result.inner);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
},
|
ntpSettings = result.inner
|
||||||
body: JSON.stringify(data)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status == 200) {
|
|
||||||
notifications.success('Security settings updated.', 3000);
|
|
||||||
ntpSettings = await response.json();
|
|
||||||
} else {
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmitNTP() {
|
function handleSubmitNTP() {
|
||||||
|
|||||||
+17
-25
@@ -5,6 +5,8 @@
|
|||||||
import { notifications } from '$lib/components/toasts/notifications';
|
import { notifications } from '$lib/components/toasts/notifications';
|
||||||
import { fade, fly } from 'svelte/transition';
|
import { fade, fly } from 'svelte/transition';
|
||||||
import Login from '~icons/tabler/login';
|
import Login from '~icons/tabler/login';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
import type { JWT } from '$lib/models';
|
||||||
|
|
||||||
type SignInData = {
|
type SignInData = {
|
||||||
password: string;
|
password: string;
|
||||||
@@ -19,31 +21,21 @@
|
|||||||
let token = { access_token: '' };
|
let token = { access_token: '' };
|
||||||
|
|
||||||
async function signInUser(data: SignInData) {
|
async function signInUser(data: SignInData) {
|
||||||
try {
|
const result = await api.post<JWT>('/api/signIn', data)
|
||||||
const response = await fetch('/api/signIn', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
username = '';
|
||||||
headers: {
|
password = '';
|
||||||
'Content-Type': 'application/json'
|
notifications.error('Wrong Username or Password!', 5000);
|
||||||
},
|
loginFailed = true;
|
||||||
body: JSON.stringify(data)
|
setTimeout(() => {
|
||||||
});
|
loginFailed = false;
|
||||||
if (response.status === 200) {
|
}, 1500);
|
||||||
token = await response.json();
|
return
|
||||||
user.init(token.access_token);
|
}
|
||||||
let username = $user.username;
|
token = result.inner;
|
||||||
notifications.success('User ' + username + ' signed in', 5000);
|
user.init(token.access_token);
|
||||||
} else {
|
username = $user.username;
|
||||||
username = '';
|
notifications.success('User ' + username + ' signed in', 5000);
|
||||||
password = '';
|
|
||||||
notifications.error('Wrong Username or Password!', 5000);
|
|
||||||
loginFailed = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
loginFailed = false;
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { telemetry } from '$lib/stores/telemetry';
|
import { telemetry } from '$lib/stores/telemetry';
|
||||||
import { openModal, closeModal } from 'svelte-modals';
|
import { openModal, closeModal } from 'svelte-modals';
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||||
import WiFiOff from '~icons/tabler/wifi-off';
|
import WiFiOff from '~icons/tabler/wifi-off';
|
||||||
import Hamburger from '~icons/tabler/menu-2';
|
import Hamburger from '~icons/tabler/menu-2';
|
||||||
@@ -13,15 +12,9 @@
|
|||||||
import UpdateIndicator from '$lib/components/UpdateIndicator.svelte';
|
import UpdateIndicator from '$lib/components/UpdateIndicator.svelte';
|
||||||
import MdiWeatherSunny from '~icons/mdi/weather-sunny';
|
import MdiWeatherSunny from '~icons/mdi/weather-sunny';
|
||||||
import MdiMoonAndStars from '~icons/mdi/moon-and-stars';
|
import MdiMoonAndStars from '~icons/mdi/moon-and-stars';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
async function postSleep() {
|
const postSleep = async () => await api.post('/api/sleep')
|
||||||
const response = await fetch('/api/sleep', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmSleep() {
|
function confirmSleep() {
|
||||||
openModal(ConfirmDialog, {
|
openModal(ConfirmDialog, {
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
import Spinner from "$lib/components/Spinner.svelte";
|
import Spinner from "$lib/components/Spinner.svelte";
|
||||||
import FolderIcon from '~icons/mdi/folder-outline';
|
import FolderIcon from '~icons/mdi/folder-outline';
|
||||||
import Folder from "./Folder.svelte";
|
import Folder from "./Folder.svelte";
|
||||||
|
import { api } from "$lib/api";
|
||||||
|
|
||||||
const getFiles = async () => {
|
const getFiles = async () => {
|
||||||
const response = await fetch('/api/files/list');
|
const result = await api.get('/api/files/list')
|
||||||
if (response.ok) {
|
if (result.isOk()) {
|
||||||
return response.json();
|
return result.inner;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -26,25 +26,25 @@
|
|||||||
import SDK from '~icons/tabler/sdk';
|
import SDK from '~icons/tabler/sdk';
|
||||||
import type { SystemInformation, Analytics } from '$lib/types/models';
|
import type { SystemInformation, Analytics } from '$lib/types/models';
|
||||||
import { socket } from '$lib/stores/socket';
|
import { socket } from '$lib/stores/socket';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
import { convertSeconds } from '$lib/utilities';
|
||||||
|
|
||||||
let systemInformation: SystemInformation;
|
let systemInformation: SystemInformation;
|
||||||
|
|
||||||
async function getSystemStatus() {
|
async function getSystemStatus() {
|
||||||
try {
|
const result = await api.get<SystemInformation>('/api/systemStatus');
|
||||||
const response = await fetch('/api/systemStatus', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
systemInformation = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
systemInformation = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Error:', error);
|
|
||||||
}
|
|
||||||
return systemInformation;
|
return systemInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const postFactoryReset = async () => await api.post('/api/factoryReset')
|
||||||
|
|
||||||
|
const postSleep = async () => await api.post('api/sleep')
|
||||||
|
|
||||||
onMount(() => socket.on('analytics', handleSystemData));
|
onMount(() => socket.on('analytics', handleSystemData));
|
||||||
|
|
||||||
onDestroy(() => socket.off('analytics', handleSystemData));
|
onDestroy(() => socket.off('analytics', handleSystemData));
|
||||||
@@ -52,14 +52,7 @@
|
|||||||
const handleSystemData = (data: Analytics) =>
|
const handleSystemData = (data: Analytics) =>
|
||||||
(systemInformation = { ...systemInformation, ...data });
|
(systemInformation = { ...systemInformation, ...data });
|
||||||
|
|
||||||
async function postRestart() {
|
const postRestart = async () => await api.post('/api/restart');
|
||||||
const response = await fetch('/api/restart', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmRestart() {
|
function confirmRestart() {
|
||||||
openModal(ConfirmDialog, {
|
openModal(ConfirmDialog, {
|
||||||
@@ -76,15 +69,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postFactoryReset() {
|
|
||||||
const response = await fetch('/api/factoryReset', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmReset() {
|
function confirmReset() {
|
||||||
openModal(ConfirmDialog, {
|
openModal(ConfirmDialog, {
|
||||||
title: 'Confirm Factory Reset',
|
title: 'Confirm Factory Reset',
|
||||||
@@ -100,15 +84,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postSleep() {
|
|
||||||
const response = await fetch('/api/sleep', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmSleep() {
|
function confirmSleep() {
|
||||||
openModal(ConfirmDialog, {
|
openModal(ConfirmDialog, {
|
||||||
title: 'Confirm Going to Sleep',
|
title: 'Confirm Going to Sleep',
|
||||||
@@ -123,33 +98,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertSeconds(seconds: number) {
|
|
||||||
// Calculate the number of seconds, minutes, hours, and days
|
|
||||||
let minutes = Math.floor(seconds / 60);
|
|
||||||
let hours = Math.floor(minutes / 60);
|
|
||||||
let days = Math.floor(hours / 24);
|
|
||||||
|
|
||||||
// Calculate the remaining hours, minutes, and seconds
|
|
||||||
hours = hours % 24;
|
|
||||||
minutes = minutes % 60;
|
|
||||||
seconds = seconds % 60;
|
|
||||||
|
|
||||||
// Create the formatted string
|
|
||||||
let result = '';
|
|
||||||
if (days > 0) {
|
|
||||||
result += days + ' day' + (days > 1 ? 's' : '') + ' ';
|
|
||||||
}
|
|
||||||
if (hours > 0) {
|
|
||||||
result += hours + ' hour' + (hours > 1 ? 's' : '') + ' ';
|
|
||||||
}
|
|
||||||
if (minutes > 0) {
|
|
||||||
result += minutes + ' minute' + (minutes > 1 ? 's' : '') + ' ';
|
|
||||||
}
|
|
||||||
result += seconds + ' second' + (seconds > 1 ? 's' : '');
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SettingsCard collapsible={false}>
|
<SettingsCard collapsible={false}>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { openModal, closeModal, closeAllModals } from 'svelte-modals';
|
import { openModal, closeModal, closeAllModals } from 'svelte-modals';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
@@ -14,43 +13,29 @@
|
|||||||
import Error from '~icons/tabler/circle-x';
|
import Error from '~icons/tabler/circle-x';
|
||||||
import { compareVersions } from 'compare-versions';
|
import { compareVersions } from 'compare-versions';
|
||||||
import GithubUpdateDialog from '$lib/components/GithubUpdateDialog.svelte';
|
import GithubUpdateDialog from '$lib/components/GithubUpdateDialog.svelte';
|
||||||
import { assets } from '$app/paths';
|
|
||||||
import InfoDialog from '$lib/components/InfoDialog.svelte';
|
import InfoDialog from '$lib/components/InfoDialog.svelte';
|
||||||
import Check from '~icons/tabler/check';
|
import Check from '~icons/tabler/check';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
async function getGithubAPI() {
|
async function getGithubAPI() {
|
||||||
try {
|
const headers = {
|
||||||
const githubResponse = await fetch(
|
accept: 'application/vnd.github+json',
|
||||||
'https://api.github.com/repos/' + $page.data.github + '/releases',
|
'X-GitHub-Api-Version': '2022-11-28'
|
||||||
{
|
}
|
||||||
method: 'GET',
|
const result = await api.get(`https://api.github.com/repos/${$page.data.github}/releases`, {headers})
|
||||||
headers: {
|
if (result.isErr()) {
|
||||||
accept: 'application/vnd.github+json',
|
console.error('Error:', result.inner);
|
||||||
'X-GitHub-Api-Version': '2022-11-28'
|
return
|
||||||
}
|
}
|
||||||
}
|
return result.inner as any;
|
||||||
);
|
|
||||||
const results = await githubResponse.json();
|
|
||||||
return results;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postGithubDownload(url: string) {
|
async function postGithubDownload(url: string) {
|
||||||
try {
|
const result = await api.post('/api/downloadUpdate', { download_url: url })
|
||||||
const apiResponse = await fetch('/api/downloadUpdate', {
|
if (result.isErr()) {
|
||||||
method: 'POST',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ download_url: url })
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmGithubUpdate(assets: any) {
|
function confirmGithubUpdate(assets: any) {
|
||||||
|
|||||||
@@ -1,30 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { openModal, closeModal } from 'svelte-modals';
|
import { openModal, closeModal } from 'svelte-modals';
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||||
import SettingsCard from '$lib/components/SettingsCard.svelte';
|
import SettingsCard from '$lib/components/SettingsCard.svelte';
|
||||||
import OTA from '~icons/tabler/file-upload';
|
import OTA from '~icons/tabler/file-upload';
|
||||||
import Warning from '~icons/tabler/alert-triangle';
|
import Warning from '~icons/tabler/alert-triangle';
|
||||||
import Cancel from '~icons/tabler/x';
|
import Cancel from '~icons/tabler/x';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
let files: FileList;
|
let files: FileList;
|
||||||
|
|
||||||
async function uploadBIN() {
|
async function uploadBIN() {
|
||||||
try {
|
const formData = new FormData();
|
||||||
const formData = new FormData();
|
formData.append('file', files[0]);
|
||||||
formData.append('file', files[0]);
|
const result = await api.post('/api/uploadFirmware', formData)
|
||||||
const response = await fetch('/api/uploadFirmware', {
|
if (result.isErr())
|
||||||
method: 'POST',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic'
|
|
||||||
},
|
|
||||||
body: formData
|
|
||||||
});
|
|
||||||
const result = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmBinUpload() {
|
function confirmBinUpload() {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
import Warning from '~icons/tabler/alert-triangle';
|
import Warning from '~icons/tabler/alert-triangle';
|
||||||
import Cancel from '~icons/tabler/x';
|
import Cancel from '~icons/tabler/x';
|
||||||
import Check from '~icons/tabler/check';
|
import Check from '~icons/tabler/check';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
type userSetting = {
|
type userSetting = {
|
||||||
username: string;
|
username: string;
|
||||||
@@ -35,63 +36,31 @@
|
|||||||
let securitySettings: SecuritySettings;
|
let securitySettings: SecuritySettings;
|
||||||
|
|
||||||
async function getSecuritySettings() {
|
async function getSecuritySettings() {
|
||||||
try {
|
const result = await api.get<SecuritySettings>('/api/securitySettings')
|
||||||
const response = await fetch('/api/securitySettings', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
securitySettings = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
securitySettings = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postSecuritySettings(data: SecuritySettings) {
|
async function postSecuritySettings(data: SecuritySettings) {
|
||||||
try {
|
const result = await api.post<SecuritySettings>('/api/securitySettings', data)
|
||||||
const response = await fetch('/api/securitySettings', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
notifications.error('User not authorized.', 3000);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
},
|
securitySettings = result.inner
|
||||||
body: JSON.stringify(data)
|
if (await validateUser()) {
|
||||||
});
|
notifications.success('Security settings updated.', 3000);
|
||||||
|
}
|
||||||
securitySettings = await response.json();
|
|
||||||
if (response.status == 200) {
|
|
||||||
if (await validateUser($user)) {
|
|
||||||
notifications.success('Security settings updated.', 3000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateUser(userdata: userProfile) {
|
async function validateUser() {
|
||||||
try {
|
const result = await api.get('/api/verifyAuthorization')
|
||||||
const response = await fetch('/api/verifyAuthorization', {
|
if (result.isErr()) user.invalidate();
|
||||||
method: 'GET',
|
return result.isOk();
|
||||||
headers: {
|
|
||||||
Authorization: 'Bearer ' + userdata.bearer_token,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (response.status !== 200) {
|
|
||||||
user.invalidate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmDelete(index: number) {
|
function confirmDelete(index: number) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import Home from '~icons/tabler/home';
|
import Home from '~icons/tabler/home';
|
||||||
import Devices from '~icons/tabler/devices';
|
import Devices from '~icons/tabler/devices';
|
||||||
import type { ApSettings, ApStatus } from '$lib/types/models';
|
import type { ApSettings, ApStatus } from '$lib/types/models';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
let apSettings: ApSettings;
|
let apSettings: ApSettings;
|
||||||
let apStatus: ApStatus;
|
let apStatus: ApStatus;
|
||||||
@@ -20,34 +21,22 @@
|
|||||||
let formField: any;
|
let formField: any;
|
||||||
|
|
||||||
async function getAPStatus() {
|
async function getAPStatus() {
|
||||||
try {
|
const result = await api.get<ApStatus>('/api/apStatus');
|
||||||
const response = await fetch('/api/apStatus', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
apStatus = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
apStatus = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return apStatus;
|
return apStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAPSettings() {
|
async function getAPSettings() {
|
||||||
try {
|
const result = await api.get<ApSettings>('/api/apSetting');
|
||||||
const response = await fetch('/api/apSettings', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error('Error:', result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
apSettings = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
apSettings = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return apSettings;
|
return apSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,24 +83,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function postAPSettings(data: ApSettings) {
|
async function postAPSettings(data: ApSettings) {
|
||||||
try {
|
const result = await api.post<ApSettings>('/api/apSettings', data);
|
||||||
const response = await fetch('/api/apSettings', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
notifications.error('User not authorized.', 3000);
|
||||||
headers: {
|
console.error('Error:', result.inner);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
},
|
notifications.success('Access Point settings updated.', 3000);
|
||||||
body: JSON.stringify(data)
|
apSettings = result.inner
|
||||||
});
|
|
||||||
if (response.status == 200) {
|
|
||||||
notifications.success('Access Point settings updated.', 3000);
|
|
||||||
apSettings = await response.json();
|
|
||||||
} else {
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmitAP() {
|
function handleSubmitAP() {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
import { closeModal } from 'svelte-modals';
|
import { closeModal } from 'svelte-modals';
|
||||||
import { focusTrap } from 'svelte-focus-trap';
|
import { focusTrap } from 'svelte-focus-trap';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import Network from '~icons/tabler/router';
|
import Network from '~icons/tabler/router';
|
||||||
import AP from '~icons/tabler/access-point';
|
import AP from '~icons/tabler/access-point';
|
||||||
import Cancel from '~icons/tabler/x';
|
import Cancel from '~icons/tabler/x';
|
||||||
@@ -11,6 +9,8 @@
|
|||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import RssiIndicator from '$lib/components/RSSIIndicator.svelte';
|
import RssiIndicator from '$lib/components/RSSIIndicator.svelte';
|
||||||
import type { NetworkItem } from '$lib/types/models';
|
import type { NetworkItem } from '$lib/types/models';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
import type { NetworkList } from '$lib/models';
|
||||||
|
|
||||||
// provided by <Modals />
|
// provided by <Modals />
|
||||||
export let isOpen: boolean;
|
export let isOpen: boolean;
|
||||||
@@ -36,13 +36,7 @@
|
|||||||
|
|
||||||
async function scanNetworks() {
|
async function scanNetworks() {
|
||||||
scanActive = true;
|
scanActive = true;
|
||||||
const scan = await fetch('/api/scanNetworks', {
|
await api.get('/api/scanNetworks');
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if ((await pollingResults()) == false) {
|
if ((await pollingResults()) == false) {
|
||||||
pollingId = setInterval(() => pollingResults(), 1000);
|
pollingId = setInterval(() => pollingResults(), 1000);
|
||||||
}
|
}
|
||||||
@@ -50,28 +44,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function pollingResults() {
|
async function pollingResults() {
|
||||||
const response = await fetch('/api/listNetworks', {
|
const result = await api.get<NetworkList>('/api/listNetworks');
|
||||||
method: 'GET',
|
if (result.isErr()){
|
||||||
headers: {
|
console.error(`Error occurred while fetching: `, result.inner);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return false
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
}
|
let response = result.inner
|
||||||
});
|
listOfNetworks = response.networks;
|
||||||
try {
|
scanActive = false;
|
||||||
const result = await response.json();
|
if (listOfNetworks.length) {
|
||||||
listOfNetworks = result.networks;
|
clearInterval(pollingId);
|
||||||
if (listOfNetworks.length) {
|
pollingId = 0;
|
||||||
scanActive = false;
|
}
|
||||||
clearInterval(pollingId);
|
return listOfNetworks.length;
|
||||||
pollingId = 0;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
scanActive = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -96,7 +81,7 @@
|
|||||||
use:focusTrap
|
use:focusTrap
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="bg-base-100 shadow rounded-box pointer-events-auto flex max-h-full min-w-fit max-w-md flex-col justify-between p-4 shadow-lg"
|
class="bg-base-100 rounded-box pointer-events-auto flex max-h-full min-w-fit max-w-md flex-col justify-between p-4 shadow-lg"
|
||||||
>
|
>
|
||||||
<h2 class="text-base-content text-start text-2xl font-bold">Scan Networks</h2>
|
<h2 class="text-base-content text-start text-2xl font-bold">Scan Networks</h2>
|
||||||
<div class="divider my-2" />
|
<div class="divider my-2" />
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
import InfoDialog from '$lib/components/InfoDialog.svelte';
|
import InfoDialog from '$lib/components/InfoDialog.svelte';
|
||||||
import type { KnownNetworkItem, WifiSettings, WifiStatus } from '$lib/types/models';
|
import type { KnownNetworkItem, WifiSettings, WifiStatus } from '$lib/types/models';
|
||||||
import { socket } from '$lib/stores';
|
import { socket } from '$lib/stores';
|
||||||
|
import { api } from '$lib/api';
|
||||||
|
|
||||||
let networkEditable: KnownNetworkItem = {
|
let networkEditable: KnownNetworkItem = {
|
||||||
ssid: '',
|
ssid: '',
|
||||||
@@ -72,35 +73,23 @@
|
|||||||
let formErrorhostname = false;
|
let formErrorhostname = false;
|
||||||
|
|
||||||
async function getWifiStatus() {
|
async function getWifiStatus() {
|
||||||
try {
|
const result = await api.get<WifiStatus>('/api/wifiStatus');
|
||||||
const response = await fetch('/api/wifiStatus', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error(`Error occurred while fetching: `, result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
wifiStatus = result.inner
|
||||||
}
|
|
||||||
});
|
|
||||||
wifiStatus = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
return wifiStatus;
|
return wifiStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getWifiSettings() {
|
async function getWifiSettings() {
|
||||||
try {
|
const result = await api.get<WifiSettings>('/api/wifiSettings');
|
||||||
const response = await fetch('/api/wifiSettings', {
|
if (result.isErr()){
|
||||||
method: 'GET',
|
console.error(`Error occurred while fetching: `, result.inner);
|
||||||
headers: {
|
return
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
}
|
||||||
'Content-Type': 'application/json'
|
wifiSettings = result.inner
|
||||||
}
|
dndNetworkList = wifiSettings.wifi_networks;
|
||||||
});
|
|
||||||
wifiSettings = await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
dndNetworkList = wifiSettings.wifi_networks;
|
|
||||||
return wifiSettings;
|
return wifiSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,24 +103,14 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function postWiFiSettings(data: WifiSettings) {
|
async function postWiFiSettings(data: WifiSettings) {
|
||||||
try {
|
const result = await api.post<WifiSettings>('/api/wifiSettings', data);
|
||||||
const response = await fetch('/api/wifiSettings', {
|
if (result.isErr()){
|
||||||
method: 'POST',
|
console.error(`Error occurred while fetching: `, result.inner);
|
||||||
headers: {
|
notifications.error('User not authorized.', 3000);
|
||||||
Authorization: $page.data.features.security ? 'Bearer ' + $user.bearer_token : 'Basic',
|
return
|
||||||
'Content-Type': 'application/json'
|
}
|
||||||
},
|
wifiSettings = result.inner
|
||||||
body: JSON.stringify(data)
|
notifications.success('Wi-Fi settings updated.', 3000);
|
||||||
});
|
|
||||||
if (response.status == 200) {
|
|
||||||
notifications.success('Wi-Fi settings updated.', 3000);
|
|
||||||
wifiSettings = await response.json();
|
|
||||||
} else {
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateHostName() {
|
function validateHostName() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
* Copyright (C) 2018 - 2023 rjwats
|
||||||
* Copyright (C) 2023 theelims
|
* Copyright (C) 2023 theelims
|
||||||
|
* Copyright (C) 2024 runeharlyk
|
||||||
*
|
*
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
* All Rights Reserved. This software may be modified and distributed under
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||||
@@ -14,74 +15,38 @@
|
|||||||
|
|
||||||
#include <FeaturesService.h>
|
#include <FeaturesService.h>
|
||||||
|
|
||||||
FeaturesService::FeaturesService(PsychicHttpServer *server) : _server(server)
|
FeaturesService::FeaturesService(PsychicHttpServer *server) : _server(server) {}
|
||||||
{
|
|
||||||
|
void FeaturesService::begin() {
|
||||||
|
_server->on(FEATURES_SERVICE_PATH, HTTP_GET, [&](PsychicRequest *request) {
|
||||||
|
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||||
|
JsonObject root = response.getRoot();
|
||||||
|
|
||||||
|
root["security"] = FT_SECURITY;
|
||||||
|
root["mqtt"] = FT_MQTT;
|
||||||
|
root["ntp"] = FT_NTP;
|
||||||
|
root["upload_firmware"] = FT_UPLOAD_FIRMWARE;
|
||||||
|
root["download_firmware"] = FT_DOWNLOAD_FIRMWARE;
|
||||||
|
root["sleep"] = FT_SLEEP;
|
||||||
|
root["battery"] = FT_BATTERY;
|
||||||
|
root["analytics"] = FT_ANALYTICS;
|
||||||
|
root["firmware_version"] = APP_VERSION;
|
||||||
|
root["firmware_name"] = APP_NAME;
|
||||||
|
root["firmware_built_target"] = BUILD_TARGET;
|
||||||
|
|
||||||
|
// Iterate over user features
|
||||||
|
for (auto &element : userFeatures) {
|
||||||
|
root[element.feature.c_str()] = element.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.send();
|
||||||
|
});
|
||||||
|
|
||||||
|
ESP_LOGV("FeaturesService", "Registered GET endpoint: %s",
|
||||||
|
FEATURES_SERVICE_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeaturesService::begin()
|
void FeaturesService::addFeature(String feature, bool enabled) {
|
||||||
{
|
|
||||||
_server->on(FEATURES_SERVICE_PATH, HTTP_GET, [&](PsychicRequest *request)
|
|
||||||
{
|
|
||||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
|
||||||
JsonObject root = response.getRoot();
|
|
||||||
|
|
||||||
#if FT_ENABLED(FT_SECURITY)
|
|
||||||
root["security"] = true;
|
|
||||||
#else
|
|
||||||
root["security"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_MQTT)
|
|
||||||
root["mqtt"] = true;
|
|
||||||
#else
|
|
||||||
root["mqtt"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_NTP)
|
|
||||||
root["ntp"] = true;
|
|
||||||
#else
|
|
||||||
root["ntp"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_UPLOAD_FIRMWARE)
|
|
||||||
root["upload_firmware"] = true;
|
|
||||||
#else
|
|
||||||
root["upload_firmware"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_DOWNLOAD_FIRMWARE)
|
|
||||||
root["download_firmware"] = true;
|
|
||||||
#else
|
|
||||||
root["download_firmware"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_SLEEP)
|
|
||||||
root["sleep"] = true;
|
|
||||||
#else
|
|
||||||
root["sleep"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_BATTERY)
|
|
||||||
root["battery"] = true;
|
|
||||||
#else
|
|
||||||
root["battery"] = false;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_ANALYTICS)
|
|
||||||
root["analytics"] = true;
|
|
||||||
#else
|
|
||||||
root["analytics"] = false;
|
|
||||||
#endif
|
|
||||||
root["firmware_version"] = APP_VERSION;
|
|
||||||
root["firmware_name"] = APP_NAME;
|
|
||||||
root["firmware_built_target"] = BUILD_TARGET;
|
|
||||||
|
|
||||||
// Iterate over user features
|
|
||||||
for (auto &element : userFeatures)
|
|
||||||
{
|
|
||||||
root[element.feature.c_str()] = element.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.send(); });
|
|
||||||
|
|
||||||
ESP_LOGV("FeaturesService", "Registered GET endpoint: %s", FEATURES_SERVICE_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FeaturesService::addFeature(String feature, bool enabled)
|
|
||||||
{
|
|
||||||
UserFeature newFeature;
|
UserFeature newFeature;
|
||||||
newFeature.feature = feature;
|
newFeature.feature = feature;
|
||||||
newFeature.enabled = enabled;
|
newFeature.enabled = enabled;
|
||||||
|
|||||||
Reference in New Issue
Block a user