Restructure project folders and remove obsolete files
All checks were successful
Deploy Spot / deploy (push) Successful in 34s

This commit is contained in:
2026-05-30 01:32:20 +02:00
parent c2685a2731
commit 034d02f042
65 changed files with 382 additions and 2165 deletions

View File

@@ -39,8 +39,8 @@ jobs:
- name: Install npm dependencies
run: npm ci
- name: Prepare runtime mount points
run: mkdir -p files geo
- name: Prepare runtime missing mount points
run: mkdir -p files resources/geo
- name: Build frontend
run: npm run prod
@@ -56,6 +56,5 @@ jobs:
--exclude "/config/settings.php" \
--exclude "/log.html" \
--exclude "/files/" \
--exclude "/geo/" \
--exclude "/gaia/" \
--exclude "/resources/geo/" \
./ "$DEPLOY_PATH/"

18
.gitignore vendored
View File

@@ -1,8 +1,16 @@
/vendor/
# App config files
/config/settings.php
/files/
/geo/
/node_modules/
/log.html
/dist/
# Upload folders
/files/
/resources/geo/*.geojson
# Build folder
/public/*
!/public/index.php
# Dependencies files
/vendor/
/node_modules/
/composer.dev.lock

View File

@@ -1,14 +1,12 @@
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const SymlinkWebpackPlugin = require('symlink-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const ROOT = path.resolve(__dirname, '..');
const SRC = path.resolve(ROOT, 'src');
const DIST = path.resolve(ROOT, 'dist');
const LIB = path.resolve(ROOT, 'lib');
const PUBLIC = path.resolve(ROOT, 'public');
module.exports = (env, argv) => {
const mode = argv.mode || 'production';
@@ -22,12 +20,12 @@ module.exports = (env, argv) => {
app: path.resolve(SRC, 'app.js')
},
output: {
path: DIST,
filename: isDev ? '[name].js' : '[name].[contenthash:8].js',
chunkFilename: isDev ? '[name].js' : '[name].[contenthash:8].js',
path: PUBLIC,
filename: isDev ? 'assets/[name].js' : 'assets/[name].[contenthash:8].js',
chunkFilename: isDev ? 'assets/[name].js' : 'assets/[name].[contenthash:8].js',
publicPath: './',
clean: {
keep: /^(files|geo|images\/icons)(\/.*)?$/
keep: /^(index\.php|files|geo|images\/icons)(\/.*)?$/
}
},
optimization: {
@@ -86,7 +84,7 @@ module.exports = (env, argv) => {
test: /\.css$/i,
use: ['vue-style-loader', 'css-loader']
}, {
test: /\.(png|svg|jpg|jpeg|gif)$/i,
test: /\.(png|svg|jpg|jpeg|gif|webp)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
@@ -94,20 +92,15 @@ module.exports = (env, argv) => {
}
},
generator: {
filename: 'images/[name].[contenthash:8][ext]'
filename: 'assets/images/[name].[contenthash:8][ext]'
}
}]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: path.resolve(LIB, 'index.php'), to: 'index.php' }
]
}),
new SymlinkWebpackPlugin([
{ origin: '../files/', symlink: 'files' },
{ origin: '../geo/', symlink: 'geo' },
{ origin: '../src/images/icons/', symlink: 'images/icons' }
{ origin: '../resources/geo/', symlink: 'geo' },
{ origin: '../src/images/icons/', symlink: 'assets/images/icons' }
]),
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: 'true',
@@ -122,7 +115,8 @@ module.exports = (env, argv) => {
chunkGroups: mapChunkGroups(stats.compilation.chunkGroups)
};
fs.writeFileSync(path.resolve(DIST, 'entrypoints.json'), JSON.stringify(manifest, null, '\t'));
fs.mkdirSync(path.resolve(PUBLIC, 'assets'), { recursive: true });
fs.writeFileSync(path.resolve(PUBLIC, 'assets', 'entrypoints.json'), JSON.stringify(manifest, null, '\t'));
});
}
},

View File

@@ -1,5 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")/.." || exit 1
php -f dist/index.php a=update_project > /dev/null
cd "$(dirname "$0")/../public" || exit 1 #Execute from public folder
php -f index.php a=update_project > /dev/null
#Crontab job: 0 * * * * /path/to/spot/cli/cron.sh > /dev/null

4
composer.lock generated
View File

@@ -12,7 +12,7 @@
"source": {
"type": "git",
"url": "https://git.lutran.fr/franzz/objects",
"reference": "d13fdacddec581b5cf5179b625f414b2453b6bf3"
"reference": "af7d0f4c86564995f1c8149df98a183d33fab767"
},
"type": "library",
"autoload": {
@@ -21,7 +21,7 @@
}
},
"description": "Objects",
"time": "2026-05-28T10:12:19+00:00"
"time": "2026-05-29T23:29:34+00:00"
},
{
"name": "phpmailer/phpmailer",

View File

@@ -5,10 +5,10 @@
DirectoryIndex index.php
# Serve http://localhost/spot/ from the compiled public bundle.
Alias /spot /var/www/html/spot/dist
# Serve http://localhost/spot/ from the public web root.
Alias /spot /var/www/html/spot/public
<Directory /var/www/html/spot/dist>
<Directory /var/www/html/spot/public>
Options FollowSymLinks
AllowOverride None
Require all granted

View File

@@ -1,38 +0,0 @@
CREATE TABLE `maps` (
`id_map` int(10) UNSIGNED auto_increment,
`codename` VARCHAR(100),
`geo_name` VARCHAR(100),
`min_zoom` TINYINT UNSIGNED,
`max_zoom` TINYINT UNSIGNED,
`attribution` VARCHAR(100),
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_map`));
CREATE TABLE `mappings` (
`id_mapping` int(10) UNSIGNED auto_increment,
`id_map` int(10) UNSIGNED,
`id_project` int(10) UNSIGNED,
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_mapping`));
ALTER TABLE mappings ADD INDEX(`id_map`);
ALTER TABLE mappings ADD FOREIGN KEY (`id_map`) REFERENCES maps(`id_map`);
ALTER TABLE mappings ADD INDEX(`id_project`);
ALTER TABLE mappings ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);
INSERT INTO maps(codename, geo_name, min_zoom, max_zoom, attribution) VALUES
/*1*/('satellite', 'mapbox.satellite-streets', 0, 19, ''),
/*2*/('otm', 'opentopomap', 2, 19, ''),
/*3*/('ign_france', 'ign.fr', 2, 19, ''),
/*4*/('ign_spain', 'ign.es', 1, 20, ''),
/*5*/('linz', 'linz', 0, 17, 'Sourced from LINZ. CC BY 4.0'),
/*6*/('usgs', 'usgs', 1, 16, ''),
/*7*/('natgeo', 'natgeo.pct', 5, 14, '');
INSERT INTO mappings(id_map, id_project) VALUES
(1, NULL),
(2, NULL),
(3, 2),
(4, 2),
(5, 1),
(6, 3);

View File

@@ -1 +0,0 @@
ALTER TABLE users ADD gravatar LONGTEXT AFTER email;

View File

@@ -1,50 +0,0 @@
ALTER TABLE medias ADD timezone CHAR(64) AFTER posted_on;
ALTER TABLE messages ADD timezone CHAR(64) AFTER site_time;
ALTER TABLE posts ADD timezone CHAR(64) AFTER site_time;
UPDATE messages
SET iso_time = DATE_FORMAT(CONVERT_TZ(LEFT(iso_time, 19),'+00:00','+02:00'), '%Y-%m-%dT%T+0200'),
led = led
WHERE id_feed = 2;
UPDATE messages
INNER JOIN feeds ON feeds.id_feed = messages.id_feed
INNER JOIN projects ON projects.id_project = feeds.id_project
SET messages.timezone = projects.timezone,
messages.led = messages.led;
UPDATE posts
SET timezone = 'Europe/Paris',
led = led;
UPDATE posts
INNER JOIN projects ON projects.id_project = posts.id_project
SET posts.id_user = 1,
posts.timezone = projects.timezone,
posts.led = posts.led
WHERE posts.name IN ('francois', 'françois','Francois', 'François', 'franzz');
UPDATE posts
SET timezone = 'Pacific/Auckland',
led = led
WHERE name = 'nz';
UPDATE posts
SET timezone = 'Atlantic/Madeira',
led = led
WHERE id_post IN (141, 142);
UPDATE medias
INNER JOIN projects ON projects.id_project = medias.id_project
SET medias.timezone = projects.timezone,
medias.led = medias.led;
UPDATE medias
SET timezone = 'Atlantic/Madeira',
taken_on = posted_on,
led = led
WHERE id_media IN (64, 65);
ALTER TABLE projects DROP COLUMN timezone;
UPDATE maps SET attribution = 'OpenTopoMap (CC-BY-SA)' WHERE id_map = 2;

View File

@@ -1,2 +0,0 @@
ALTER TABLE users ADD clearance TINYINT(1) DEFAULT 0 AFTER active;
UPDATE users SET clearance = 9 WHERE email = 'francois.lutran@gmail.com';

View File

@@ -1,2 +0,0 @@
ALTER TABLE messages ADD posted_on TIMESTAMP DEFAULT 0 AFTER battery_state;
UPDATE messages SET posted_on = led, led = led;

View File

@@ -1,3 +0,0 @@
ALTER TABLE messages ADD weather_icon VARCHAR(30) AFTER posted_on;
ALTER TABLE messages ADD weather_cond VARCHAR(30) AFTER weather_icon;
ALTER TABLE messages ADD weather_temp DECIMAL(3,1) AFTER weather_cond;

View File

@@ -1,4 +0,0 @@
INSERT INTO maps (codename, geo_name, min_zoom, max_zoom, attribution) VALUES ('outdoors', 'mapbox.outdoors', 0, 19, '');
ALTER TABLE maps ADD COLUMN tile_size SMALLINT UNSIGNED DEFAULT 256 AFTER geo_name;
UPDATE maps SET tile_size = 512 WHERE geo_name = 'mapbox.outdoors';
UPDATE maps SET tile_size = 512 WHERE geo_name = 'mapbox.satellite-streets';

View File

@@ -1,15 +0,0 @@
ALTER TABLE maps ADD pattern VARCHAR(200) NOT NULL AFTER geo_name;
UPDATE maps SET pattern = CONCAT('http://localhost/geo/?a=tile&id=', geo_name, '&z={z}&x={x}&y={y}') WHERE geo_name <> '';
ALTER TABLE maps ADD token VARCHAR(4096) AFTER pattern;
UPDATE maps SET token = '';
ALTER TABLE maps DROP geo_name;
INSERT INTO maps (codename, pattern, token, tile_size, min_zoom, max_zoom, attribution)
VALUES ('static', 'http://localhost/geo/?a=tile&id=static&z=13&x={x}&y={y}', '', 400, 13, 13, '');
INSERT INTO maps (codename, pattern, token, tile_size, min_zoom, max_zoom, attribution)
VALUES ('static_marker', 'http://localhost/geo/?a=tile&id=static.marker&z=13&x={x}&y={y}&marker=http://localhost/spot/images/footprint_mapbox.png', '', 400, 13, 13, '');
UPDATE maps SET max_zoom = 17 WHERE codename = 'otm';

View File

@@ -1,233 +0,0 @@
ALTER TABLE medias ADD width INT AFTER timezone;
ALTER TABLE medias ADD height INT AFTER width;
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (1).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (10).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (11).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (12).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (13).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (14).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (15).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (16).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (17).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (18).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (19).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (2).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (20).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (21).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (22).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (23).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (24).jpg';
UPDATE medias SET width = 640, height = 1136 WHERE filename = 'image (25).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (26).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (27).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (28).jpg';
UPDATE medias SET width = 960, height = 1280 WHERE filename = 'image (29).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (3).jpg';
UPDATE medias SET width = 960, height = 1280 WHERE filename = 'image (30).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (31).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (32).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (33).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (34).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (35).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (36).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (37).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (38).jpg';
UPDATE medias SET width = 2048, height = 1365 WHERE filename = 'image (39).jpg';
UPDATE medias SET width = 1280, height = 960 WHERE filename = 'image (4).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (40).jpg';
UPDATE medias SET width = 8192, height = 1856 WHERE filename = 'image (41).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (42).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (43).jpg';
UPDATE medias SET width = 8192, height = 1856 WHERE filename = 'image (44).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (45).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (46).jpg';
UPDATE medias SET width = 640, height = 1038 WHERE filename = 'image (47).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (48).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (49).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (5).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (50).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (51).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (52).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (53).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (54).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (55).jpg';
UPDATE medias SET width = 3648, height = 5472 WHERE filename = 'image (56).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (57).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (58).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (59).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (6).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (60).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (61).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (62).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'image (63).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'image (7).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (8).jpg';
UPDATE medias SET width = 2448, height = 3264 WHERE filename = 'image (9).jpg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'DSC01187[1].JPG';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'DSC01477.JPG';
UPDATE medias SET width = 2726, height = 4089 WHERE filename = 'DSC03114.jpg';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_6011.MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = '156E315D-88AD-492C-BE97-9854FED48FF7.MOV';
UPDATE medias SET width = 2576, height = 1932 WHERE filename = '4D06AAF9-A244-4AEF-A1B0-A3C439673840.jpeg';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '06361CBA-F514-4789-A498-47D681881DDF.MOV';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'B0A15DCC-B5BB-4BE3-ADBA-CBCB51C178F6.jpeg';
UPDATE medias SET width = 1280, height = 720 WHERE filename = 'F827F48B-5CC4-4DA7-A80B-FFED47F6EC60.MOV';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'EC407D2D-0ECF-46C7-BC05-73F48D152182.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '7961DA2D-288D-4B0B-B4A6-400673E23BA6.jpeg';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'B43B0160-DAB4-433A-9064-918C40744D27.MOV';
UPDATE medias SET width = 1536, height = 2134 WHERE filename = 'C0D5CCF6-FE72-424C-A040-96D8C34FBE9E.jpeg';
UPDATE medias SET width = 2154, height = 1850 WHERE filename = '0940EF97-4C27-4304-A663-654F0DE5FAB2.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '7597DEC0-1BD3-4B93-926B-E4D8A4B28E61.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '3A1F777D-58F6-40BA-8AAE-1EA236581BA3.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'C6AC86F9-C819-4866-AA71-A31375E4CCC4.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'B936E022-4D70-4C9E-9EAE-308FB6F91816.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'C777A1C7-7C3A-4ADC-8A5C-CEE8FB047B79.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'B76D8452-FCC4-4FCE-8686-2A4B8C7832FF.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '313F8490-E885-42F5-BB59-ACFB12250F0F.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'F0C1EFDB-0A4F-4FC0-A46D-A396D8724054.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'E9339EEF-A21C-48A6-B6CC-23C3A512DA29.jpeg';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '5150FFEF-A715-4F5A-8562-1502BE778B6A.MOV';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'C8CD8B78-3EC9-4700-9A46-478556496239.jpeg';
UPDATE medias SET width = 1536, height = 2048 WHERE filename = '3D83F7D3-B746-440F-8DD3-6DADF230AC28.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'B9121A78-0B21-42E2-8392-A60BCE240EFE.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '5A3755D0-81CB-43B1-9750-AB34F413D526.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'B9EFBC4F-4FC4-4D03-9722-9A1FF61F3B8E.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'F7C6FFFF-BF61-42BF-949B-72CD2CAAEFE2.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'B0557309-579D-4C1A-863F-CF4898C42E77.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '2C75F8E9-C3E0-4FD5-AF2E-CE339545D6BC.jpeg';
UPDATE medias SET width = 3891, height = 2917 WHERE filename = 'C6E18BC2-B407-4F2C-82F9-87244A9AD311.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '0A4B5812-D5CD-4CB0-989B-C95D15526F1A.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '1548CCA0-C8C8-4DC6-BD96-ABAA4589E825.jpeg';
UPDATE medias SET width = 4685, height = 3116 WHERE filename = '7F80807F-D40F-4714-81AE-3CD7CD3FE8CD.jpeg';
UPDATE medias SET width = 5283, height = 3519 WHERE filename = '32F5B460-958D-4A13-92BD-371BBC0DA769.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'F99EEC87-C5CC-49AD-BCBF-8A14ADADD262.jpeg';
UPDATE medias SET width = 8192, height = 1856 WHERE filename = 'C243E61F-2A31-4179-97B4-AD54C02E88D5.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '85807A81-91CB-4B10-861B-1B3C5A60F066.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'DE99B389-738F-48CB-BEF1-D448DEB16E7E.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '6BBD7291-BDFC-460F-A620-9D2F68AF637F.jpeg';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '7DB6662E-353A-4AC5-9331-D9122D956FE7.MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = '974841E5-AB13-4067-AD5F-3EDEFEAE28E4.MOV';
UPDATE medias SET width = 1536, height = 2304 WHERE filename = '09F007C7-53BA-4214-B3AF-DB0E0CDD1994.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '6B92D63D-EDA5-4787-8AC7-4A0F65DC071F.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'BAF3BB55-E012-40CD-8D8B-27C4398C1D00.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '8FA2F4F0-F220-4E98-9BC0-ACB607FC2F8E.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'C260B1AD-BA4C-4835-B132-A529A9319D4D.jpeg';
UPDATE medias SET width = 1536, height = 2304 WHERE filename = '92F8E35B-5FF8-414D-A627-46FF45E6CCCA.jpeg';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '33AA17D3-CFD6-426A-B2D5-CD639F53C081.MOV';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '0015713D-18A2-45A7-B26F-3954AC0979D3.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '223A23C5-71BB-4419-8765-CE51F3E69480.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '9ED663DD-0257-4211-A993-C86CDAC9066B.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '1ECF5050-8821-441C-8DF7-E93B24941F8A.jpeg';
UPDATE medias SET width = 1536, height = 2304 WHERE filename = '68211D98-D6E7-4D7C-BB82-7E5E30884C7D.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '61747CFA-859E-4859-852F-3AE2650C7578.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'F17CD761-DFDC-4E5F-97A7-C16035A8D8EB.jpeg';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = '7EE0B25A-0BC6-4BF1-9CDF-9E4547CFEAF4.MOV';
UPDATE medias SET width = 3503, height = 2625 WHERE filename = '273092DD-F6CE-4C74-8878-A4D94A9C78F9.jpeg';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '4853B2CB-5BC4-45FE-AD02-0980953DB59A.MOV';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '789210A7-293D-4119-87EE-1B7CA0ACBE0A.jpeg';
UPDATE medias SET width = 2665, height = 1996 WHERE filename = '52D57195-22A2-423B-AA35-05D48B889950.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'F5644C0F-5244-4574-BBE1-4059794F87E1.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = '7BB3D57A-D5BE-45D5-8CAC-C3172A89C67A.jpeg';
UPDATE medias SET width = 2687, height = 2013 WHERE filename = '8345C480-1274-45DB-A990-40913DD219A7.jpeg';
UPDATE medias SET width = 4128, height = 3096 WHERE filename = '28567B3E-A067-41AE-AE69-37DD3C98F820.jpeg';
UPDATE medias SET width = 3096, height = 4128 WHERE filename = '20190827_133201_DxO.jpg';
UPDATE medias SET width = 3096, height = 4128 WHERE filename = '20190827_133201_DxO (1).jpg';
UPDATE medias SET width = 3096, height = 4128 WHERE filename = '20190827_133201_DxO (2).jpg';
UPDATE medias SET width = 3096, height = 4128 WHERE filename = '20190827_133201_DxO (3).jpg';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled.png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (1).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (2).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (3).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (4).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (5).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (6).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (7).png';
UPDATE medias SET width = 2000, height = 3000 WHERE filename = 'Untitled (8).png';
UPDATE medias SET width = 365, height = 600 WHERE filename = 'asunabg.png';
UPDATE medias SET width = 365, height = 600 WHERE filename = 'asunabg (1).png';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'iPhone 6S (1).jpeg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'IMG_2591.JPG';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'CF0432E7-5221-433D-A681-DBABE131EE99.jpeg';
UPDATE medias SET width = 694, height = 628 WHERE filename = 'Capture.PNG';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'IMG_2232 (1).jpg';
UPDATE medias SET width = 1350, height = 900 WHERE filename = 'Photo 2014-06-21 20-17-11 (_MG_1217).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (9).jpg';
UPDATE medias SET width = 1154, height = 770 WHERE filename = 'Photo 2014-06-21 20-17-11 (_MG_1217)_DxO (3).jpg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'IMG_2232 (2).jpg';
UPDATE medias SET width = 2320, height = 3088 WHERE filename = '9C0965E1-6A40-4691-8127-35B2F1D6BB58.jpeg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'IMG_3077.jpg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'AF7A1DBC-E1CC-4FEE-8411-AC25BF69C0B5.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'F7FC1246-6304-4662-A5F2-230A29728EBC.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'CA5BA9A6-2A53-430A-A0BF-B8D0C0CDC983.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '12E87114-6B4B-4051-945C-9042FBBF5E3E.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'F97B5058-C7D7-4B25-B727-914A8897CE58.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'D1E626E6-6F49-4F62-A3D5-B19CBC906F7B.jpeg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'IMG_1228_DxO.jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'IMG_1268_DxO.jpg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = 'IMG_2232.jpg';
UPDATE medias SET width = 2475, height = 2475 WHERE filename = 'IMG_2232_DxO (1).jpg';
UPDATE medias SET width = 2475, height = 2475 WHERE filename = 'IMG_2232_DxO.jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'IMG_2317.jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'IMG_2574 (1).jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'IMG_2574 (2).jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'IMG_2574.jpg';
UPDATE medias SET width = 1344, height = 672 WHERE filename = 'PHOTO-2019-12-24-23-40-26.jpg';
UPDATE medias SET width = 1512, height = 2688 WHERE filename = 'PXL_20210405_083835976.jpg';
UPDATE medias SET width = 3840, height = 2160 WHERE filename = 'PXL_20210405_091516836.jpg';
UPDATE medias SET width = 1350, height = 900 WHERE filename = 'Photo 2014-06-21 20-17-11 (_MG_1217)_DxO (1).jpg';
UPDATE medias SET width = 1350, height = 900 WHERE filename = 'Photo 2014-06-21 20-17-11 (_MG_1217)_DxO (2).jpg';
UPDATE medias SET width = 1350, height = 900 WHERE filename = 'Photo 2014-06-21 20-17-11 (_MG_1217)_DxO.jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (1).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (2).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (3).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (4).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (5).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (6).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (7).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945) (8).jpg';
UPDATE medias SET width = 2000, height = 1500 WHERE filename = 'Photo 2015-01-11 20-30-03 (P1020945).jpg';
UPDATE medias SET width = 1500, height = 2000 WHERE filename = 'Photo 2015-01-19 19-59-34 (P1040055).jpg';
UPDATE medias SET width = 3264, height = 2448 WHERE filename = 'TEST.jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'image (64).jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'image (65).jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'image.jpg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '083932A9-4248-4208-91CC-34DCDC374E7A.jpeg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = '102ED557-69B0-41F2-9193-DF52FEEFD35C.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '45289F93-5D82-40DE-A0B1-1871317C56C1.jpeg';
UPDATE medias SET width = 1200, height = 1600 WHERE filename = '5F97CB55-46C7-4BB7-9335-BBDFF77F1310.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '634716D8-D7E7-4128-B0D2-EEB4437411F3.jpeg';
UPDATE medias SET width = 3024, height = 4032 WHERE filename = '6C111386-591F-450D-9794-E812FB6FF036.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '6D718B33-020D-460A-9194-D637A2590ABC.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '866196A9-5428-4E6C-8C4A-03DB284A9448.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'A68E6383-095C-4CB2-876B-4EC59DB24419.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'APPLE (1).jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'APPLE.jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'B9EFBC4F-4FC4-4D03-9722-9A1FF61F3B8E (1).jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'B9EFBC4F-4FC4-4D03-9722-9A1FF61F3B8E (2).jpeg';
UPDATE medias SET width = 5472, height = 3648 WHERE filename = 'B9EFBC4F-4FC4-4D03-9722-9A1FF61F3B8E (3).jpeg';
UPDATE medias SET width = 1152, height = 1536 WHERE filename = 'BA37E256-C0B2-4DE6-B0E0-659EB2C3411B.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'D4009C41-7B4C-42D5-9FB4-9CEC7CC1B4B0.jpeg';
UPDATE medias SET width = 1200, height = 1600 WHERE filename = 'DDFADE5F-2785-4168-9EAB-D63818566929.jpeg';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = 'iPhone 6S.jpeg';
UPDATE medias SET width = 365, height = 600 WHERE filename = 'asunabg (2).png';
UPDATE medias SET width = 365, height = 600 WHERE filename = 'asunabg (3).png';
UPDATE medias SET width = 365, height = 600 WHERE filename = 'asunabg (4).png';
UPDATE medias SET width = 200, height = 120 WHERE filename = 'ffprobeall.png';
UPDATE medias SET width = 1280, height = 720 WHERE filename = 'temp_60a6954ea732b.png';
UPDATE medias SET width = 1280, height = 720 WHERE filename = 'temp_60a695501d507.png';
UPDATE medias SET width = 1080, height = 1920 WHERE filename = 'temp_60a695509009d.png';
UPDATE medias SET width = 1080, height = 1920 WHERE filename = 'temp_60a695520a9a0.png';
UPDATE medias SET width = 1080, height = 1920 WHERE filename = 'temp_60a695535d689.png';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '7DB6662E-353A-4AC5-9331-D9122D956FE7 (1).MOV';
UPDATE medias SET width = 1280, height = 720 WHERE filename = '7DB6662E-353A-4AC5-9331-D9122D956FE7 (2).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2584 (1).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2584.MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2585 (1).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2585 (2).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2585 (3).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2585 (4).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2585 (5).MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'IMG_2585.MOV';
UPDATE medias SET width = 1920, height = 1080 WHERE filename = 'iPhone 6S.MOV';
UPDATE medias SET width = 4032, height = 3024 WHERE filename = '1620E5B9-C65D-4252-A495-18D5CAD63C6E.jpeg';

View File

@@ -1,5 +0,0 @@
ALTER TABLE messages MODIFY ref_msg_id VARCHAR(15) NOT NULL;
ALTER TABLE messages ADD display BOOLEAN DEFAULT 1 AFTER weather_temp;
UPDATE messages SET display = 0 WHERE id_message = 197;
UPDATE messages SET display = 0 WHERE id_message = 216;

View File

@@ -1,25 +0,0 @@
CREATE TABLE `projects` (
`id_project` int(10) UNSIGNED auto_increment,
`codename` VARCHAR(100),
`name` VARCHAR(100),
`active_from` DATETIME,
`active_to` DATETIME,
`geofile` VARCHAR(50),
`timezone` VARCHAR(100),
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_project`));
INSERT INTO projects (name, codename, active_from, active_to, geofile, timezone) VALUES ('Te Araroa', 'te_araroa', '2015-12-29 00:00:00', '2016-03-05 23:59:59', 'te_araroa.geojson', 'Pacific/Auckland');
INSERT INTO projects (name, codename, active_from, active_to, geofile, timezone) VALUES ('HRP', 'hrp', '2019-06-01 00:00:00', '2019-09-10 23:59:59', 'hrp.geojson', 'Europe/Paris');
ALTER TABLE feeds ADD COLUMN id_project int(10) UNSIGNED AFTER id_spot;
ALTER TABLE feeds ADD last_update DATETIME AFTER status;
ALTER TABLE feeds ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);
UPDATE feeds SET last_update = led;
UPDATE feeds SET id_project = 1;
ALTER TABLE posts ADD COLUMN id_project int(10) UNSIGNED AFTER id_post;
ALTER TABLE posts ADD timestamp DATETIME AFTER content;
ALTER TABLE posts ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);
UPDATE posts SET timestamp = led;
UPDATE posts SET id_project = 1;

View File

@@ -1,3 +0,0 @@
ALTER TABLE medias ADD latitude DECIMAL(7,5) AFTER timezone;
ALTER TABLE medias ADD longitude DECIMAL(8,5) AFTER latitude;
ALTER TABLE medias ADD altitude SMALLINT AFTER longitude;

View File

@@ -1,5 +0,0 @@
ALTER TABLE mappings ADD COLUMN default_map BOOLEAN DEFAULT 0 AFTER id_project;
ALTER TABLE mappings ADD CONSTRAINT default_on_generic_map_only CHECK (default_map = 0 OR id_project IS NULL);
UPDATE mappings SET default_map = 1 WHERE id_map = (select id_map from maps where codename = 'satellite');
UPDATE maps SET token = substring(pattern, locate('token=', pattern) + 6) WHERE codename = 'static_marker';
UPDATE maps SET pattern = replace(pattern, token, '{token}') WHERE codename = 'static_marker';

View File

@@ -1,23 +0,0 @@
ALTER TABLE medias MODIFY latitude DECIMAL(8,6);
ALTER TABLE medias MODIFY longitude DECIMAL(9,6);
UPDATE medias SET comment = 'Source chaude en plein milieu d''une forêt !' WHERE id_media = 16;
UPDATE medias SET comment = 'Stephan veut absolument arriver à Arrowtown avant le Super Bowl :D' WHERE id_media = 48;
UPDATE medias SET latitude = 41.011880, longitude = -121.652212, altitude = 855 WHERE id_media = 286;
UPDATE medias SET latitude = -41.787646,longitude = 172.886950 WHERE id_media = 62;
UPDATE medias SET latitude = -43.575937,longitude = 170.945159, comment = 'Edoras' WHERE id_media = 17;
UPDATE medias SET latitude = -44.176388,longitude = 170.196363, comment = 'Juste la bonne ouverture !' WHERE id_media = 29;
UPDATE medias SET latitude = -43.695997,longitude = 170.168364, comment = 'Tasman Glacier' WHERE id_media = 31;
UPDATE medias SET latitude = -44.802931,longitude = 168.157397 WHERE id_media = 52;
UPDATE medias SET latitude = 42.475460, longitude = 3.040459 WHERE id_media = 70;
UPDATE medias SET latitude = 42.701617, longitude = 0.526217 WHERE id_media = 104;
UPDATE medias SET latitude = 42.715667, longitude = 0.028215 WHERE id_media = 107;
UPDATE medias SET latitude = 42.691005, longitude = -0.033730 WHERE id_media = 114;
UPDATE medias SET latitude = 42.789225, longitude = -0.155126 WHERE id_media = 122;
UPDATE medias SET latitude = 43.085268, longitude = -1.389657 WHERE id_media = 127;
UPDATE medias SET latitude = 43.307165, longitude = -1.630111 WHERE id_media = 129;
UPDATE medias SET latitude = 57.278450, longitude = -5.289557 WHERE id_media = 396;
UPDATE medias SET latitude = 58.208948, longitude = -4.927144, comment = 'Eas a'' Chual Aluinn (nom de la chute deau, cest du gaélique, faut pas chercher). Les plus hautes des UK.' WHERE id_media = 409;
UPDATE medias SET latitude = 58.243837, longitude = -4.964172 WHERE id_media = 410;
UPDATE medias SET latitude = 58.542221, longitude = -5.048463 WHERE id_media = 417;

View File

@@ -1,2 +0,0 @@
ALTER TABLE projects ADD latitude DECIMAL(8,6) AFTER name;
ALTER TABLE projects ADD longitude DECIMAL(9,6) AFTER latitude;

View File

@@ -1,14 +0,0 @@
CREATE TABLE `pictures` (
`id_picture` int(10) UNSIGNED auto_increment,
`id_project` int(10) UNSIGNED,
`filename` VARCHAR(100) NOT NULL,
`taken_on` DATETIME,
`timestamp` DATETIME,
`rotate` SMALLINT,
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_picture`),
UNIQUE KEY `uni_file_name` (`filename`)
);
ALTER TABLE pictures ADD INDEX(`id_project`);
ALTER TABLE pictures ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);

View File

@@ -1,15 +0,0 @@
ALTER TABLE messages ADD iso_time VARCHAR(24) AFTER longitude;
ALTER TABLE messages CHANGE COLUMN timestamp site_time TIMESTAMP DEFAULT 0;
ALTER TABLE messages CHANGE COLUMN unix_timestamp unix_time INT;
UPDATE messages SET iso_time = CONCAT(REPLACE(CONVERT_TZ(FROM_UNIXTIME(unix_time), @@session.time_zone, 'Pacific/Auckland'), ' ', 'T'), '+1200') WHERE id_feed = 1;
ALTER TABLE feeds MODIFY last_update TIMESTAMP DEFAULT 0;
ALTER TABLE projects MODIFY active_from TIMESTAMP DEFAULT 0;
ALTER TABLE projects MODIFY active_to TIMESTAMP DEFAULT 0;
ALTER TABLE posts CHANGE COLUMN timestamp site_time TIMESTAMP DEFAULT 0;
ALTER TABLE pictures CHANGE COLUMN timestamp posted_on TIMESTAMP DEFAULT 0;
UPDATE pictures INNER JOIN projects USING(id_project) SET taken_on = CONVERT_TZ(taken_on, projects.timezone, @@session.time_zone) where id_project = 1;
ALTER TABLE pictures MODIFY taken_on TIMESTAMP DEFAULT 0;

View File

@@ -1 +0,0 @@
UPDATE projects SET geofile = REPLACE(geofile, '.geojson', '');

View File

@@ -1,4 +0,0 @@
RENAME TABLE pictures TO medias;
ALTER TABLE medias CHANGE COLUMN id_picture id_media INT(10) UNSIGNED NOT NULL auto_increment;
ALTER TABLE medias ADD COLUMN type VARCHAR(20) AFTER filename;
UPDATE medias SET type = 'image';

View File

@@ -1,2 +0,0 @@
/* Remove NO_ZERO_DATE mode, checks mode with: SELECT @@SQL_MODE, @@GLOBAL.SQL_MODE; and: SET @@SQL_MODE = REPLACE(@@SQL_MODE, 'NO_ZERO_DATE', ''); */
ALTER TABLE medias ADD comment LONGTEXT AFTER rotate;

View File

@@ -1 +0,0 @@
ALTER TABLE projects DROP COLUMN geofile;

View File

@@ -1,14 +0,0 @@
CREATE TABLE `users` (
`id_user` int(10) UNSIGNED auto_increment,
`name` VARCHAR(100),
`email` VARCHAR(320),
`language` VARCHAR(2),
`active` BOOLEAN,
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_user`),
UNIQUE KEY `uni_email` (`email`)
);
ALTER TABLE posts ADD COLUMN id_user int(10) UNSIGNED AFTER id_project;
ALTER TABLE posts ADD INDEX(`id_user`);
ALTER TABLE posts ADD FOREIGN KEY (`id_user`) REFERENCES users(`id_user`);

View File

@@ -1,5 +0,0 @@
ALTER TABLE users ADD COLUMN timezone char(64) AFTER language;
ALTER TABLE users MODIFY COLUMN email VARCHAR(320) NOT NULL;
UPDATE users SET timezone = 'Europe/Paris';
ALTER TABLE projects MODIFY COLUMN timezone char(64);

File diff suppressed because one or more lines are too long

View File

@@ -1,782 +0,0 @@
// ==UserScript==
// @name GaiaGps Uploader
// @namespace https://greasyfork.org/users/583371
// @description Allow the user to upload multiple files at once and more than 1000 waypoints
// @grant none
// @version 3.1.2
// @author Franzz
// @license GNU GPLv3
// @match https://www.gaiagps.com/map/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js
// ==/UserScript==
/* jshint esversion: 6 */
//Ctrl+Alt+Shift+I to open network tab on addon
/* GPXParser - v3.0.8 - https://github.com/Luuka/GPXParser.js/blob/master/src/GPXParser.js */
/* Personnal modifications have been applied, care on upgrade */
/**
* GPX file parser
*
* @constructor
*/
let gpxParser = function () {
this.xmlSource = "";
this.metadata = {};
this.waypoints = [];
this.tracks = [];
this.routes = [];
};
/**
* Parse a gpx formatted string to a GPXParser Object
*
* @param {string} gpxstring - A GPX formatted String
*
* @return {gpxParser} A GPXParser object
*/
gpxParser.prototype.parse = function (gpxstring) {
let keepThis = this;
let domParser = new window.DOMParser();
this.xmlSource = domParser.parseFromString(gpxstring, 'text/xml');
let metadata = this.xmlSource.querySelector('metadata');
if(metadata != null){
this.metadata.name = this.getElementValue(metadata, "name");
this.metadata.desc = this.getElementValue(metadata, "desc");
this.metadata.time = this.getElementValue(metadata, "time");
let author = {};
let authorElem = metadata.querySelector('author');
if(authorElem != null){
author.name = this.getElementValue(authorElem, "name");
author.email = {};
let emailElem = authorElem.querySelector('email');
if(emailElem != null){
author.email.id = emailElem.getAttribute("id");
author.email.domain = emailElem.getAttribute("domain");
}
let link = {};
let linkElem = authorElem.querySelector('link');
if(linkElem != null){
link.href = linkElem.getAttribute('href');
link.text = this.getElementValue(linkElem, "text");
link.type = this.getElementValue(linkElem, "type");
}
author.link = link;
}
this.metadata.author = author;
let link = {};
let linkElem = this.queryDirectSelector(metadata, 'link');
if(linkElem != null){
link.href = linkElem.getAttribute('href');
link.text = this.getElementValue(linkElem, "text");
link.type = this.getElementValue(linkElem, "type");
this.metadata.link = link;
}
}
var wpts = [].slice.call(this.xmlSource.querySelectorAll('wpt'));
for (let idx in wpts){
var wpt = wpts[idx];
let pt = {};
pt.name = keepThis.getElementValue(wpt, "name");
pt.lat = parseFloat(wpt.getAttribute("lat"));
pt.lon = parseFloat(wpt.getAttribute("lon"));
//let floatValue = parseFloat(keepThis.getElementValue(wpt, "ele"));
//pt.ele = isNaN(floatValue) ? null : floatValue;
pt.ele = parseFloat(keepThis.getElementValue(wpt, "ele")) || null;
pt.cmt = keepThis.getElementValue(wpt, "cmt");
pt.desc = keepThis.getElementValue(wpt, "desc");
pt.sym = keepThis.getElementValue(wpt, "sym");
//let time = keepThis.getElementValue(wpt, "time");
//pt.time = time == null ? null : new Date(time);
pt.time = (keepThis.getElementValue(wpt, "time") || keepThis.metadata.time) || null;
keepThis.waypoints.push(pt);
}
var rtes = [].slice.call(this.xmlSource.querySelectorAll('rte'));
for (let idx in rtes){
let rte = rtes[idx];
let route = {};
route.name = keepThis.getElementValue(rte, "name");
route.cmt = keepThis.getElementValue(rte, "cmt");
route.desc = keepThis.getElementValue(rte, "desc");
route.src = keepThis.getElementValue(rte, "src");
route.number= keepThis.getElementValue(rte, "number");
let type = keepThis.queryDirectSelector(rte, "type");
route.type = type != null ? type.innerHTML : null;
let link = {};
let linkElem= rte.querySelector('link');
if(linkElem != null){
link.href = linkElem.getAttribute('href');
link.text = keepThis.getElementValue(linkElem, "text");
link.type = keepThis.getElementValue(linkElem, "type");
}
route.link = link;
let routepoints = [];
var rtepts = [].slice.call(rte.querySelectorAll('rtept'));
for (let idxIn in rtepts){
let rtept = rtepts[idxIn];
let pt = {};
pt.lat = parseFloat(rtept.getAttribute("lat"));
pt.lon = parseFloat(rtept.getAttribute("lon"));
//let floatValue = parseFloat(keepThis.getElementValue(rtept, "ele"));
//pt.ele = isNaN(floatValue) ? null : floatValue;
pt.ele = parseFloat(keepThis.getElementValue(rtept, "ele")) || null;
//let time = keepThis.getElementValue(rtept, "time");
//pt.time = time == null ? null : new Date(time);
pt.time = (keepThis.getElementValue(rtept, "time") || keepThis.metadata.time) || null;
routepoints.push(pt);
}
//route.distance = keepThis.calculDistance(routepoints);
//route.elevation = keepThis.calcElevation(routepoints);
//route.slopes = keepThis.calculSlope(routepoints, route.distance.cumul);
route.points = routepoints;
keepThis.routes.push(route);
}
var trks = [].slice.call(this.xmlSource.querySelectorAll('trk'));
for (let idx in trks){
let trk = trks[idx];
let track = {};
track.name = keepThis.getElementValue(trk, "name");
track.cmt = keepThis.getElementValue(trk, "cmt");
track.desc = keepThis.getElementValue(trk, "desc");
track.src = keepThis.getElementValue(trk, "src");
track.number= keepThis.getElementValue(trk, "number");
track.color = keepThis.getElementValue(trk, "DisplayColor");
track.time = keepThis.metadata.time;
let type = keepThis.queryDirectSelector(trk, "type");
track.type = type != null ? type.innerHTML : null;
let link = {};
let linkElem= trk.querySelector('link');
if(linkElem != null){
link.href = linkElem.getAttribute('href');
link.text = keepThis.getElementValue(linkElem, "text");
link.type = keepThis.getElementValue(linkElem, "type");
}
track.link = link;
let trackpoints = [];
let trkpts = [].slice.call(trk.querySelectorAll('trkpt'));
for (let idxIn in trkpts){
var trkpt = trkpts[idxIn];
let pt = {};
pt.lat = parseFloat(trkpt.getAttribute("lat"));
pt.lon = parseFloat(trkpt.getAttribute("lon"));
//let floatValue = parseFloat(keepThis.getElementValue(trkpt, "ele"));
//pt.ele = isNaN(floatValue) ? null : floatValue;
pt.ele = parseFloat(keepThis.getElementValue(trkpt, "ele")) || null;
//let time = keepThis.getElementValue(trkpt, "time");
//pt.time = time == null ? null : new Date(time);
pt.time = (keepThis.getElementValue(trkpt, "time") || keepThis.metadata.time) || null;
trackpoints.push(pt);
}
//track.distance = keepThis.calculDistance(trackpoints);
//track.elevation = keepThis.calcElevation(trackpoints);
//track.slopes = keepThis.calculSlope(trackpoints, track.distance.cumul);
track.points = trackpoints;
keepThis.tracks.push(track);
}
};
/**
* Get value from a XML DOM element
*
* @param {Element} parent - Parent DOM Element
* @param {string} needle - Name of the searched element
*
* @return {} The element value
*/
gpxParser.prototype.getElementValue = function(parent, needle){
let elem = parent.querySelector(needle);
if(elem != null){
//Get value (in case of CDATA)
let sValue = (elem.innerHTML != undefined && elem.innerHTML.substring(0, 8) != '<![CDATA') ? elem.innerHTML : elem.childNodes[0].data;
//If decoded HTML, re-encode
if(sValue.substr(0, 4)== '&lt;') sValue = $('<div>').html(sValue).text();
//Strip HTML tags & trim value
return $('<div>').html(sValue).text().trim();
}
return elem;
};
/**
* Search the value of a direct child XML DOM element
*
* @param {Element} parent - Parent DOM Element
* @param {string} needle - Name of the searched element
*
* @return {} The element value
*/
gpxParser.prototype.queryDirectSelector = function(parent, needle) {
let elements = parent.querySelectorAll(needle);
let finalElem = elements[0];
if(elements.length > 1) {
let directChilds = parent.childNodes;
for(idx in directChilds) {
elem = directChilds[idx];
if(elem.tagName === needle) {
finalElem = elem;
}
}
}
return finalElem;
};
class Gaia {
static get URL() { return 'https://www.gaiagps.com'; }
static get API() { return Gaia.URL+'/api/objects'; }
constructor() {
this.reset();
}
reset() {
this.asFiles = [];
this.aoWaypoints = [];
this.aoTracks = [];
this.asFolders = {};
this.progress = {current:0, total:0};
}
setLayout() {
this.reset();
/* FIXME: adapts on GaiaGPS upgrade */
let $InputButton = $('a[href="https://help.gaiagps.com/hc/en-us/articles/360052763513"]').parent().find('button');
//If the button is found (=displayed)
if($InputButton.length > 0) {
this.$InputBox = $InputButton.parent();
//Add Feedback box
this.$Feedback = ($('#ggu-feedback').length > 0)?$('#ggu-feedback'):($('<div>', {
'id':'ggu-feedback',
'style':'width:calc(100% + 64px); height:400px; margin:1em 0 0 -32px; display:inline-block; text-align:left; overflow:auto;'
}).insertAfter($InputButton));
/*
//Add Folder Name Input next to button
this.$InputName = ($('#ggu-inputname').length > 0)?$('#ggu-inputname'):($('<input>', {
'type':'text',
'id': 'ggu-inputname',
'name':'ggu-inputname',
'placeholder':'Folder Name',
'style': 'border-width:2px; border-color:rgba(0, 0, 0, 0.1); border-radius:4px; font-family:Inter,Helvetica Neue,Helvetica,Arial; font-size:15px; padding:8px 12px; margin-bottom:12px;'
}).val('PCT').prependTo(this.$InputBox));
*/
//Reset File Input DOM Element
let $InputFile = $('input[type=file]');
this.$InputFile = $InputFile.clone()
.insertAfter($InputFile)
.attr('multiple', 'multiple')
.attr('name', 'files[]')
.change(() => { this.readInputFiles(); });
$InputFile.remove();
//Reset button
this.$InputButton = $InputButton.clone()
.insertAfter($InputButton)
.click(() => {this.$InputFile.click();});
$InputButton.remove();
//Clear all upload notifications
this.resetNotif();
}
}
feedback(sType, sMsg) {
let sColor = 'black';
let sIcon = '';
switch(sType) {
case 'error': sColor = 'red'; sIcon = '\u274C'; break;
case 'warning': sColor = 'orange'; sIcon = '\u26A0'; break;
case 'info': sColor = '#2D5E38'; sIcon = '\u2713'; break;
}
var sFormattedMsg = sIcon+' '+sMsg+(sMsg.slice(-1)=='.'?'':'.');
console.log(sFormattedMsg);
this.$Feedback.append($('<p>', {'style': 'color: '+sColor+';'}).text(sFormattedMsg));
this.$Feedback.scrollTop(this.$Feedback.prop("scrollHeight"));
}
incProgress() {
if(!this.progress.current) {
this.progress.$Done = $('<div>', {'style':'overflow:hidden; background:#2D5E38; color: white; text-align:right;'});
this.progress.$Left = $('<div>', {'style':'overflow:hidden; background:white; color: #2D5E38; text-align:left;'});
this.progress.$Box = $('<div>', {'id':'ggu-progress', 'style':'margin-top:1em;'})
.append($('<div>', {'style':'display:flex; width:calc(100% + 64px); margin-left:-32px; border-radius:3px; border: 1px solid #2D5E38; box-sizing: border-box;'})
.append(this.progress.$Done)
.append(this.progress.$Left)
);
this.$Feedback.before(this.progress.$Box);
}
this.progress.current++;
if(this.progress.current < this.progress.total) {
let iRatio = Math.round(this.progress.current / this.progress.total * 100);
let sTextDone = '', sTextLeft = '';
if(iRatio < 50) {
sTextDone = '';
sTextLeft = '&nbsp;'+iRatio+'% ('+this.progress.current+' / '+this.progress.total+')';
}
else {
sTextDone = '('+this.progress.current+' / '+this.progress.total+') '+iRatio+'%&nbsp;';
sTextLeft = '';
}
this.progress.$Done.css('flex', iRatio+' 1 0%').html(sTextDone);
this.progress.$Left.css('flex', (100 - iRatio)+' 1 0%').html(sTextLeft);
}
else {
this.progress.$Box.remove();
this.progress = {current:0, total:0};
}
}
//Marking all upload notifications as read
resetNotif() {
this.feedback('info', 'Marking all upload notifications as read');
$.get(Gaia.URL+'/social/notifications/popup/').done((asNotifs) => {
for(var i in asNotifs) {
if(!asNotifs[i].isViewed && asNotifs[i].html.indexOf('has completed') != -1) {
$.post(Gaia.URL+'/social/notifications/'+asNotifs[i].id+'/markviewed/');
}
}
});
}
//Parse files from input (multiple)
readInputFiles() {
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
this.feedback('error', 'File APIs are not fully supported in this browser');
return;
}
else this.feedback('info', 'Parsing input files');
//Get Folder Name (text input)
let aoReaders = [];
let iCount = 0;
this.asFiles = this.$InputFile.prop('files');
for(var i=0 ; i < this.asFiles.length ; i++) {
aoReaders[i] = new FileReader();
aoReaders[i].onload = ((oFileReader) => {
return (asResult) => {
iCount++;
this.feedback('info', 'Reading file "'+oFileReader.name+'" ('+iCount+'/'+this.asFiles.length+')');
this.parseFile(oFileReader.name, asResult.target.result);
this.asFolders[oFileReader.name] = {};
if(iCount == this.asFiles.length) {
this.progress.total = this.aoTracks.length + this.aoWaypoints.length + this.asFiles.length; //extra action per file: Create folder
this.createFolders();
}
};
})(this.asFiles[i]);
aoReaders[i].readAsText(this.asFiles[i]);
}
}
//Parse GPX files to consolidate tracks & waypoints
parseFile(sFileName, oContent) {
this.feedback('info', 'Parsing file "'+sFileName+'"');
var oGPX = new gpxParser();
oGPX.parse(oContent);
//Waypoints
for(var w in oGPX.waypoints) {
oGPX.waypoints[w].filename = sFileName;
var sWaypointName = oGPX.waypoints[w].name;
/* if(sWaypointName.indexOf('Milestone - ') != -1 && sWaypointName.substr(-2) != '00') { //1 milestone every 100 miles
this.feedback('info', 'Ignoring milestone waypoint "'+sWaypointName+'"');
}
else */this.aoWaypoints.push(oGPX.waypoints[w]);
}
//Tracks
for(var t in oGPX.tracks) {
oGPX.tracks[t].filename = sFileName;
this.aoTracks.push(oGPX.tracks[t]);
}
}
//Delete existing folder with same name & recreating it
createFolders() {
let iCount = 0;
$.each(this.asFolders, (sFileName, asFolder) => {
//Folder Name
let sFolderName = sFileName.replace(/\.[^\.]+$/, '');
this.feedback('info', 'Looking for existing folder "'+sFolderName+'"...');
$.get(Gaia.API+'/folder/?search='+sFolderName).done((asFolders) => {
if(asFolders != '' && !$.isEmptyObject(asFolders)) {
for(var f in asFolders) {
this.feedback('info', 'Deleting "'+asFolders[f].title+'" folder');
$.ajax({
url: Gaia.API+'/folder/'+asFolders[f].id+'/',
type: 'DELETE'
});
}
}
else this.feedback('info', 'No folder named "'+sFolderName+'" found');
this.feedback('info', 'Creating folder "'+sFolderName+'"');
let sTime = (new Date()).toISOString();
$.post({
url: Gaia.API+'/folder/',
contentType: 'application/json',
data: JSON.stringify({
title: sFolderName,
imported: true
})
}).done((asFolder) => {
this.feedback('info', 'Folder "'+asFolder.properties.name+'" created');
this.asFolders[sFileName] = asFolder;
this.incProgress();
iCount++;
if(iCount == Object.keys(this.asFolders).length) this.uploadTrack();
}).fail(() => {
this.feedback('error', 'Folder "'+sFolderName+'" could not be created');
});
});
});
}
//Build & Upload Track File
uploadTrack(iIndex) {
iIndex = iIndex || 0;
if(iIndex == 0) this.feedback('info', 'Uploading tracks...');
let aoTrack = this.aoTracks[iIndex];
this.feedback('info', 'Uploading track "'+aoTrack.name+'"');
let sColor = '#4ABD32';
switch(aoTrack.color) {
//Personal Colors
case 'DarkBlue': sColor = '#2D3FC7'; break;
case 'Magenta': sColor = '#B60DC3'; break;
//Garmin Colors
case 'Black': sColor = '#000000'; break;
case 'DarkRed': sColor = '#F90553'; break;
case 'DarkGreen': sColor = '#009B89'; break;
case 'DarkYellow': sColor = '#DCEE0E'; break;
//case 'DarkBlue': sColor = '#5E23CA'; break;
case 'DarkMagenta': sColor = '#B60DC3'; break;
case 'DarkCyan': sColor = '#00ACF8'; break;
case 'LightGray': sColor = '#A4A4A4'; break;
case 'DarkGray': sColor = '#577B8E'; break;
case 'Red': sColor = '#F90553'; break;
case 'Green': sColor = '#36C03B'; break;
case 'Yellow': sColor = '#FFF011'; break;
case 'Blue': sColor = '#2D3FC7'; break;
//case 'Magenta': sColor = '#B60DC3'; break;
case 'Cyan': sColor = '#00C3DD'; break;
case 'White': sColor = '#FFFFFF'; break;
case 'Transparent': sColor = '#784D3E'; break;
}
//Add track points
let aoCoords = [];
for(var p in aoTrack.points) {
let pt = aoTrack.points[p];
aoCoords.push([pt.lon, pt.lat, pt.ele, 0]);
}
//Convert to geojson
let sPostedData = JSON.stringify({
geometry: {
coordinates: [aoCoords],
type: 'MultiLineString'
},
properties: {
archived: false,
color: sColor,
//distance: 168405.62350073704,
filename: aoTrack.filename,
hexcolor: sColor,
isLatestImport: true,
isLocallyCreated: true,
isPublicTrack: false,
isValid: true,
localId: 'track'+(iIndex + 1),
notes: aoTrack.desc,
parent_folder_id: this.asFolders[aoTrack.filename].id,
routing_mode: null,
time_created: aoTrack.time || (new Date()).toISOString(),
title: aoTrack.name,
type: 'track',
writable: true
},
type: 'Feature'
});
var self = this;
$.post({
url: Gaia.API+'/track/',
contentType: 'application/json',
data: sPostedData,
trackName: aoTrack.name
}).done(function(asTrack) {
self.aoTracks[iIndex] = asTrack;
self.confirmTrack(iIndex, asTrack, this.data);
}).fail(function() {
self.feedback('error', 'Track "'+this.trackName+'" upload failed (stage 1). Retrying...');
self.uploadTrack(iIndex);
});
}
confirmTrack(iIndex, asTrack, sPostedData) {
iIndex = iIndex || 0;
var self = this;
$.ajax({
url: Gaia.API+'/track/'+asTrack.features[0].id+'/',
type: 'PUT',
contentType: 'application/json',
data: sPostedData,
trackName: asTrack.features[0].properties.title
}).done(function() {
self.feedback('info', 'Track "'+this.trackName+'" uploaded');
self.incProgress();
iIndex++;
if(iIndex < self.aoTracks.length) self.uploadTrack(iIndex);
else {
self.feedback('info', 'All tracks uploaded');
self.uploadWayPoints();
}
}).fail(function() {
self.feedback('error', 'Track "'+this.trackName+'" upload failed (stage 2). Retrying...');
self.confirmTrack(iIndex, asTrack, sPostedData);
});
}
/*
//Wait for file to be processed by Gaia
checkNotif() {
this.feedback('info', 'Waiting for Gaia to process consolidated track');
$.get(Gaia.URL+'/social/notifications/popup/').done((asNotifs) => {
for(var i in asNotifs) {
if(!asNotifs[i].isViewed && asNotifs[i].html.indexOf('has completed') != -1) {
this.feedback('info', 'Notification '+asNotifs[i].id+' found. Marking as read');
var $Notif = $('<span>').html(asNotifs[i].html);
this.sFolderId = $Notif.find('a').attr('href').split('/')[3];
$.post(Gaia.URL+'/social/notifications/'+asNotifs[i].id+'/markviewed/');
}
}
if(this.sFolderId != '') {
this.setTracksColor();
this.uploadWayPoints();
}
else setTimeout((() => {this.checkNotif();}), 1000);
});
}
*/
uploadWayPoints(iIndex) {
iIndex = iIndex || 0;
//Upload waypoints
var sWaypointName = this.aoWaypoints[iIndex].name;
var aoWaypoint = this.aoWaypoints[iIndex];
this.feedback('info', 'Uploading waypoint '+(iIndex + 1)+'/'+this.aoWaypoints.length+' ('+aoWaypoint.name+')');
var asPost = {
geometry: {
coordinates: [
aoWaypoint.lon,
aoWaypoint.lat,
aoWaypoint.ele
],
type: 'Point'
},
properties: {
archived: false,
filename: aoWaypoint.filename,
icon: Gaia.getIconName(aoWaypoint.sym),
isLatestImport: true,
isLocallyCreated: true,
isValid: true,
localId: iIndex+'',
notes: aoWaypoint.desc,
parent_folder_id: this.asFolders[aoWaypoint.filename].id,
time_created: aoWaypoint.time || (new Date()).toISOString(),
title: aoWaypoint.name,
type: 'waypoint',
writable: true
},
type: 'Feature'
};
let sData = JSON.stringify(asPost);
var self = this;
$.post({
url: Gaia.API+'/waypoint/',
contentType: 'application/json',
data: sData
}).done(function(asWaypoint) {
self.aoWaypoints[iIndex] = asWaypoint;
self.confirmWayPoint(iIndex, asWaypoint, this.data);
}).fail(function(){
self.feedback('error', 'Failed to upload waypoint #'+(iIndex + 1)+' "'+sWaypointName+'" (Stage 1). Trying again...');
self.uploadWayPoints(iIndex);
});
}
confirmWayPoint(iIndex, asWaypoint, sPostedData) {
$.ajax({
url: Gaia.API+'/waypoint/'+asWaypoint.properties.id+'/',
type: 'PUT',
contentType: 'application/json',
data: sPostedData
}).done(() => {
iIndex++;
this.incProgress();
if(iIndex < this.aoWaypoints.length) this.uploadWayPoints(iIndex);
//else this.assignElementsToFolders();
else this.feedback('info', 'Done');
}).fail(() => {
this.feedback('error', 'Failed to upload waypoint #'+(iIndex + 1)+' "'+asWaypoint.properties.title+'" (Stage 2). Trying again...');
this.confirmWayPoint(iIndex, asWaypoint, sPostedData);
});
}
/*
assignElementsToFolders(iIndex) {
iIndex = iIndex || 0;
let asFolders = Object.keys(this.asFolders).map(key => this.asFolders[key]);
let asFolder = asFolders[iIndex];
this.feedback('info', 'Assigning elements of folder "'+asFolder.properties.name+'"');
//Folder metadata
let asData = {
cover_photo_id: asFolder.properties.cover_photo_id,
id: asFolder.id,
name: asFolder.properties.name,
notes: asFolder.properties.notes,
time_created: asFolder.properties.time_created,
updated_date: asFolder.properties.updated_date
}
//Assign waypoints to folder
asData.waypoints = [];
for(var w in this.aoWaypoints) {
if(this.aoWaypoints[w].parent_folder_id = asFolder.id) asData.waypoints.push(this.aoWaypoints[w].properties.id);
}
//Assign tracks to folder
asData.tracks = [];
for(var t in this.aoTracks) {
if(this.aoTracks[t].parent_folder_id = asFolder.id) asData.tracks.push(this.aoTracks[t].features[0].id);
}
$.ajax({
url: Gaia.API+'/folder/'+asFolder.id+'/',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(asData)
}).done(() => {
iIndex++;
this.incProgress();
this.feedback('info', 'Tracks & waypoints assigned to folder "'+asFolder.properties.name+'"');
if(iIndex < asFolders.length) this.assignElementsToFolders(iIndex);
else this.feedback('info', 'Done');
}).fail(() => {
this.feedback('warning', 'Failed to assign waypoints & tracks to folder "'+asFolder.properties.name+'". Trying again...');
this.assignElementsToFolders(iIndex);
});
}
*/
static getIconName(sGarminName) {
var asMapping = {
'Bridge': 'bridge',
'Campground': 'campsite-24',
'Car': 'car-24',
'Cemetery': 'cemetery-24',
'Church': 'ghost-town',
'City (Capitol)': 'city-24',
'Convenience Store': 'market',
'Drinking Water': 'potable-water',
'Flag, Blue': 'blue-pin-down',
'Flag, Green': 'green-pin',
'Flag, Red': 'red-pin-down',
'Forest': 'forest',
'Ground Transportation': 'car-24',
'Lodging': 'lodging-24',
'Park': 'park-24',
'Pharmacy': 'hospital-24',
'Picnic Area': 'picnic',
'Post Office': 'resupply',
'Powerline': 'petroglyph',
'Residence': 'building-24',
'Restaurant': 'restaurant-24',
'Restroom': 'toilets-24',
'Shopping Center': 'market',
'Ski Resort': 'skiing-24',
'Summit': 'peak',
'Toll Booth': 'ranger-station',
'Trail Head': 'known-route',
'Truck': 'car-24',
'Water Source': 'water-24'
};
return (sGarminName in asMapping)?asMapping[sGarminName]:'red-pin-down';
}
}
console.log('Loading GaiaGps Uploader '+GM_info.script.version);
let oGaia = new Gaia();
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
let observer = new MutationObserver((mutations, observer) => {
/* FIXME: adapts on GaiaGPS upgrade */
let $Import = $('div[aria-label="Import Data"]');
if($Import.length > 0) {
observer.disconnect();
$Import.parent('li').on('click', () => { setTimeout(() => { oGaia.setLayout(); }, 500)});
}
});
observer.observe(document, { subtree: true, attributes: true});

File diff suppressed because one or more lines are too long

168
lib/Controller.php Normal file
View File

@@ -0,0 +1,168 @@
<?php
namespace Franzz\Spot;
use Franzz\Objects\PhpObject;
use Franzz\Objects\ToolBox;
//TODO Keep only local specificities and move bulk to Franzz\Objects\Controller
class Controller extends PhpObject
{
const MUTATING_ACTIONS = array(
'add_post',
'subscribe',
'unsubscribe',
'update_project',
'upload',
'add_comment',
'add_position',
'admin_set',
'admin_create',
'admin_delete',
'build_geojson'
);
private Spot $oSpot;
private array $asReq;
private string $sCsrfToken = '';
public function __construct()
{
parent::__construct(__CLASS__);
}
private function setReqVal(string $sKey, $oValue, string $sValidation=''): void
{
$this->asReq[$sKey] = $this->validateValue($sValidation, $oValue);
}
public function handle($sProcessPage, array $argv = array()): string
{
//Start buffering so warnings/notices can be collected
ob_start();
//Parse variables
$asReq = ToolBox::getRequest($argv);
$this->asReq = array();
$sAction = $asReq['a'] ?? '';
$this->setReqVal('t', $asReq['t'] ?? '');
$this->setReqVal('name', $asReq['name'] ?? '');
$this->setReqVal('content', $asReq['content'] ?? '');
$this->setReqVal('id_project', $asReq['id_project'] ?? 0, 'positiveInt');
$this->setReqVal('id', $asReq['id'] ?? 0);
$this->setReqVal('id_entity', $asReq['id'] ?? 0, 'positiveInt');
$this->setReqVal('field', $asReq['field'] ?? '');
$this->setReqVal('value', $asReq['value'] ?? '');
$this->setReqVal('type', $asReq['type'] ?? '');
$this->setReqVal('email', $asReq['email'] ?? '');
$this->setReqVal('latitude', $asReq['latitude'] ?? '');
$this->setReqVal('longitude', $asReq['longitude'] ?? '');
$this->setReqVal('timestamp', $asReq['timestamp'] ?? 0, 'positiveInt');
$this->setReqVal('csrf_token', $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ($_POST['csrf_token'] ?? ''));
//Create Spot Instance
$this->oSpot = new Spot($sProcessPage, $this->asReq['t']);
$this->oSpot->setProjectId($this->asReq['id_project']);
//Validate CSRF & dispatch
if(!$this->validateMutationRequest($sAction)) $sResult = Spot::getJsonResult(false, Spot::UNAUTHORIZED);
elseif($sAction == '') $sResult = $this->oSpot->getAppMainPage($this->getCsrfToken());
else $sResult = $this->dispatch($sAction);
//Clean errors
$sDebug = ob_get_clean();
if($sDebug != '') $this->oSpot->addUncaughtError($sDebug);
return $sResult;
}
private function validateMutationRequest(string $sAction): bool
{
return
PHP_SAPI === 'cli'
||
!in_array($sAction, self::MUTATING_ACTIONS, true)
||
($_SERVER['REQUEST_METHOD'] ?? '') === 'POST' && $this->checkCsrfToken($this->asReq['csrf_token'])
;
}
private function getCsrfToken(): string
{
if($this->sCsrfToken === '') $this->initCsrfToken();
return $this->sCsrfToken;
}
private function setCsrfToken(): void
{
if(empty($_SESSION['csrf_token'])) $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
$this->sCsrfToken = $_SESSION['csrf_token'];
}
private function initCsrfToken(): void
{
if(PHP_SAPI === 'cli') return;
$bCloseSession = false;
if(session_status() !== PHP_SESSION_ACTIVE) {
$bSecure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https');
session_set_cookie_params(array('httponly' => true, 'secure' => $bSecure, 'samesite' => 'Lax'));
session_start();
$bCloseSession = true;
}
$this->setCsrfToken();
if($bCloseSession) session_write_close();
}
private function checkCsrfToken(string $sClientToken): bool
{
$sServerToken = $this->getCsrfToken();
return PHP_SAPI === 'cli' || ($sServerToken !== '' && is_string($sClientToken) && hash_equals($sServerToken, $sClientToken));
}
private function dispatch(string $sAction): string
{
return match($sAction) {
'markers' => $this->oSpot->getMarkers(),
'last_update' => $this->oSpot->getLastUpdate(),
'geojson' => $this->oSpot->getProjectGeoJson(),
'next_feed' => $this->oSpot->getNextFeed($this->asReq['id']),
'new_feed' => $this->oSpot->getNewFeed($this->asReq['id']),
'add_post' => $this->oSpot->addPost($this->asReq['name'], $this->asReq['content']),
'subscribe' => $this->oSpot->subscribe($this->asReq['email'], $this->asReq['name']),
'unsubscribe' => $this->oSpot->unsubscribe(),
'unsubscribe_email' => $this->oSpot->unsubscribeFromEmail($this->asReq['id_entity']),
'update_project' => $this->oSpot->updateProject(),
default => $this->dispatchAdmin($sAction)
};
}
private function dispatchAdmin(string $sAction): string
{
if(!$this->oSpot->checkUserClearance(User::CLEARANCE_ADMIN)) {
return Spot::getJsonResult(false, Spot::NOT_FOUND);
}
return match($sAction) {
'upload' => $this->oSpot->upload(),
'add_comment' => $this->oSpot->addComment($this->asReq['id_entity'], $this->asReq['content']),
'add_position' => $this->oSpot->addPosition($this->asReq['latitude'], $this->asReq['longitude'], $this->asReq['timestamp']),
'admin_get' => $this->oSpot->getAdminSettings(),
'admin_set' => $this->oSpot->setAdminSettings($this->asReq['type'], $this->asReq['id_entity'], $this->asReq['field'], $this->asReq['value']),
'admin_create' => $this->oSpot->createAdminSettings($this->asReq['type']),
'admin_delete' => $this->oSpot->deleteAdminSettings($this->asReq['type'], $this->asReq['id_entity']),
'sql' => $this->oSpot->getDbBuildScript(),
'build_geojson' => $this->oSpot->buildGeoJSON($this->asReq['name']),
default => Spot::getJsonResult(false, Spot::NOT_FOUND)
};
}
private static function validateValue(string $sValidation, $oValue=0)
{
return match($sValidation) {
'' => $oValue,
'positiveInt' => filter_var($oValue, FILTER_VALIDATE_INT, array('options' => array('default' => 0, 'min_range' => 0)))
};
}
}

View File

@@ -36,8 +36,8 @@ class Converter extends PhpObject {
}
public static function isGeoJsonValid($sCodeName) {
$sGpxFilePath = Gpx::getFilePath($sCodeName);
$sGeoJsonFilePath = GeoJson::getFilePath($sCodeName);
$sGpxFilePath = Gpx::getBackendFilePath($sCodeName);
$sGeoJsonFilePath = GeoJson::getBackendFilePath($sCodeName);
//No need to generate if gpx is missing
return !file_exists($sGpxFilePath) || file_exists($sGeoJsonFilePath) && filemtime($sGeoJsonFilePath) >= filemtime($sGpxFilePath);

View File

@@ -4,26 +4,29 @@ namespace Franzz\Spot;
use Franzz\Objects\PhpObject;
use \Settings;
class Geo extends PhpObject {
abstract class Geo extends PhpObject {
protected const EXT = '';
const GEO_FOLDER = '../geo/';
const GEO_FOLDER = 'geo';
const OPT_SIMPLE = 'simplification';
protected $asTracks;
protected $sFilePath;
protected array $asTracks;
protected string $sFilePath;
public function __construct($sCodeName) {
public function __construct(string $sCodeName) {
parent::__construct(get_class($this), Settings::DEBUG, PhpObject::MODE_HTML);
$this->sFilePath = self::getFilePath($sCodeName);
$this->sFilePath = self::getBackEndFilePath($sCodeName);
$this->asTracks = array();
}
public static function getFilePath($sCodeName) {
return self::GEO_FOLDER.$sCodeName.static::EXT;
//Access from backend
public static function getBackendFilePath(string $sCodeName) {
return '../resources/'.self::GEO_FOLDER.'/'.$sCodeName.static::EXT;
}
public static function getDistFilePath($sCodeName) {
return 'geo/'.$sCodeName.static::EXT;
//Access from frontend (/public/geo is a symlink of /resources/geo)
public static function getFrontendFilePath(string $sCodeName) {
return self::GEO_FOLDER.'/'.$sCodeName.static::EXT;
}
public function getLog() {

View File

@@ -11,9 +11,9 @@ class Media extends PhpObject {
//DB Tables
const MEDIA_TABLE = 'medias';
//Media folders
const MEDIA_FOLDER = 'files/';
const THUMB_FOLDER = self::MEDIA_FOLDER.'thumbs/';
//Media folders (works because /public/files is a symlink of /files)
const MEDIA_FOLDER = 'files';
const THUMB_FOLDER = self::MEDIA_FOLDER.'/thumbs';
const THUMB_MAX_WIDTH = 400;
@@ -288,8 +288,8 @@ class Media extends PhpObject {
}
private static function getMediaPath($sMediaName, $sFileType='media') {
if($sFileType=='thumbnail') return self::THUMB_FOLDER.$sMediaName.(strtolower(substr($sMediaName, -3))=='mov'?'.png':'');
else return self::MEDIA_FOLDER.$sMediaName;
if($sFileType=='thumbnail') return self::THUMB_FOLDER.'/'.$sMediaName.(strtolower(substr($sMediaName, -3))=='mov'?'.png':'');
else return self::MEDIA_FOLDER.'/'.$sMediaName;
}
private static function getMediaType($sMediaName) {

View File

@@ -144,7 +144,7 @@ class Project extends PhpObject {
case 2: $asProject['mode'] = self::MODE_HISTO; break;
}
$asProject['editable'] = $this->isModeEditable($asProject['mode']);
$asProject['gpxfilepath'] = Spot::addTimestampToFilePath(Gpx::getDistFilePath($sCodeName));
$asProject['gpxfilepath'] = Spot::addTimestampToFilePath(Gpx::getFrontendFilePath($sCodeName));
$asProject['codename'] = $sCodeName;
$asProject['default'] = ($sCodeName == $sDefaultProjectCodeName);
}
@@ -157,7 +157,7 @@ class Project extends PhpObject {
$this->oDb->updateRow(self::PROJ_TABLE, $this->iProjectId, ['latitude' => $aiCenter[1], 'longitude' => $aiCenter[0]]);
}
return json_decode(file_get_contents(GeoJson::getDistFilePath($this->sCodeName)), true);
return json_decode(file_get_contents(GeoJson::getBackendFilePath($this->sCodeName)), true);
}
public function getProject() {

View File

@@ -45,21 +45,6 @@ class Spot extends Main
const MAIN_PAGE = 'index';
const DIST_FOLDER = '../dist/';
const MUTATING_ACTIONS = array(
'add_post',
'subscribe',
'unsubscribe',
'update_project',
'upload',
'add_comment',
'add_position',
'admin_set',
'admin_create',
'admin_delete',
'build_geojson'
);
private Project $oProject;
private Media $oMedia;
private User $oUser;
@@ -179,14 +164,7 @@ class Spot extends Main
);
}
public function getAppMainPage() {
//Cache Page List
$asPages = array_diff($this->asMasks, array('email.update', 'email.confirmation'));
if(!$this->oUser->checkUserClearance(User::CLEARANCE_ADMIN)) {
$asPages = array_diff($asPages, array('admin', 'upload'));
}
public function getAppMainPage(string $sCsrfToken='') {
return parent::getMainPage(
array(
'projects' => $this->oProject->getProjects(),
@@ -200,7 +178,7 @@ class Spot extends Main
'hash_sep' => '-',
'title' => self::PROJECT_NAME,
'default_page' => 'project',
'csrf_token' => $this->getCsrfToken()
'csrf_token' => $sCsrfToken
)
),
self::MAIN_PAGE,
@@ -212,15 +190,14 @@ class Spot extends Main
'instances' => [
'entrypoint' => $this->getAppEntryPoints()
]
),
$asPages
)
);
}
private function getAppEntryPoints() {
return array_map(
function($sFileName) {return ['filename' => self::addTimestampToFilePath($sFileName)];},
json_decode(file_get_contents(self::DIST_FOLDER.'entrypoints.json'), true)['entrypoints']['app']
json_decode(file_get_contents('assets/entrypoints.json'), true)['entrypoints']['app']
);
}

View File

@@ -6,19 +6,10 @@ use Franzz\Objects\Translator;
class Uploader extends UploadHandler
{
/**
* Medias Management
* @var Media
*/
private $oMedia;
private Media $oMedia;
private Translator $oLang;
/**
* Languages
* @var Translator
*/
private $oLang;
public $sBody;
public string $sBody;
function __construct(Media &$oMedia, Translator &$oLang)
{
@@ -27,7 +18,7 @@ class Uploader extends UploadHandler
$this->sBody = '';
parent::__construct(array(
'upload_dir' => Media::MEDIA_FOLDER,
'upload_dir' => Media::MEDIA_FOLDER.'/',
'image_versions' => array(),
'accept_file_types' => '/\.(gif|jpe?g|png|mov|mp4)$/i'
));

View File

@@ -1,118 +0,0 @@
<?php
/* Requests Handler */
//Start buffering
ob_start();
//Run from /dist/
$oLoader = require __DIR__.'/../vendor/autoload.php';
use Franzz\Objects\ToolBox;
use Franzz\Spot\Spot;
use Franzz\Spot\User;
ToolBox::fixGlobalVars($argv ?? array());
//Available variables
$sAction = $_REQUEST['a'] ?? '';
$sTimezone = $_REQUEST['t'] ?? '';
$sName = $_REQUEST['name'] ?? '';
$sContent = $_REQUEST['content'] ?? '';
$iProjectId = Spot::validatePositiveInt($_REQUEST['id_project'] ?? 0);
$sRefId = $_REQUEST['id'] ?? 0;
$iEntityId = Spot::validatePositiveInt($_REQUEST['id'] ?? 0);
$sField = $_REQUEST['field'] ?? '';
$oValue = $_REQUEST['value'] ?? '';
$sType = $_REQUEST['type'] ?? '';
$sEmail = $_REQUEST['email'] ?? '';
$sLat = $_REQUEST['latitude'] ?? '';
$sLng = $_REQUEST['longitude'] ?? '';
$iTimestamp = Spot::validatePositiveInt($_REQUEST['timestamp'] ?? 0);
$sCsrfToken = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ($_POST['csrf_token'] ?? '');
//Initiate class
$oSpot = new Spot(__FILE__, $sTimezone);
$oSpot->setProjectId($iProjectId);
$bValidRequest = $oSpot->validateMutationRequest($sAction, $sCsrfToken);
if(!$bValidRequest) $sResult = Spot::getJsonResult(false, Spot::UNAUTHORIZED);
elseif($sAction == '') $sResult = $oSpot->getAppMainPage();
else
{
switch($sAction)
{
case 'markers':
$sResult = $oSpot->getMarkers();
break;
case 'last_update':
$sResult = $oSpot->getLastUpdate();
break;
case 'geojson':
$sResult = $oSpot->getProjectGeoJson();
break;
case 'next_feed':
$sResult = $oSpot->getNextFeed($sRefId);
break;
case 'new_feed':
$sResult = $oSpot->getNewFeed($sRefId);
break;
case 'add_post':
$sResult = $oSpot->addPost($sName, $sContent);
break;
case 'subscribe':
$sResult = $oSpot->subscribe($sEmail, $sName);
break;
case 'unsubscribe':
$sResult = $oSpot->unsubscribe();
break;
case 'unsubscribe_email':
$sResult = $oSpot->unsubscribeFromEmail($iEntityId);
break;
case 'update_project':
$sResult = $oSpot->updateProject();
break;
default:
if($oSpot->checkUserClearance(User::CLEARANCE_ADMIN))
{
switch($sAction)
{
case 'upload':
$sResult = $oSpot->upload();
break;
case 'add_comment':
$sResult = $oSpot->addComment($iEntityId, $sContent);
break;
case 'add_position':
$sResult = $oSpot->addPosition($sLat, $sLng, $iTimestamp);
break;
case 'admin_get':
$sResult = $oSpot->getAdminSettings();
break;
case 'admin_set':
$sResult = $oSpot->setAdminSettings($sType, $iEntityId, $sField, $oValue);
break;
case 'admin_create':
$sResult = $oSpot->createAdminSettings($sType);
break;
case 'admin_delete':
$sResult = $oSpot->deleteAdminSettings($sType, $iEntityId);
break;
case 'sql':
$sResult = $oSpot->getDbBuildScript();
break;
case 'build_geojson':
$sResult = $oSpot->buildGeoJSON($sName);
break;
default:
$sResult = Spot::getJsonResult(false, Spot::NOT_FOUND);
}
}
else $sResult = Spot::getJsonResult(false, Spot::NOT_FOUND);
}
}
$sDebug = ob_get_clean();
if(Settings::DEBUG && $sDebug!='') $oSpot->addUncaughtError($sDebug);
echo $sResult;

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
<title>[#]lang:email.confirmation.subject[#]</title>
</head>
<body>
<span style="color: transparent; display: none !important; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">[#]lang:email.confirmation.preheader[#]</span>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="width:100%;max-width:600px;">
<tr>
<td width="20%"><img src="[#]local_server[#]images/icons/mstile-144x144.png" width="90%" border="0" alt="logo" /></td>
<td><h1>[#]lang:email.confirmation.thanks_subject[#]</h1></td>
</tr>
<tr>
<td colspan="2">
<p align="justify">[#]lang:email.confirmation.body_1[#]</p>
<p align="justify">[#]lang:email.confirmation.body_2[#]</p>
<p align="justify">[#]lang:email.confirmation.body_3[#]</p>
</td>
</tr>
<tr>
<td colspan="2">
<p>[#]lang:email.confirmation.conclusion[#]<br />[#]lang:email.confirmation.signature[#]</p>
</td>
</tr>
<tr>
<td colspan="2">
<p>[#]lang:email.unsubscribe[#] <a href="[#]unsubscribe_link[#]" target="_blank" rel="noopener">[#]lang:email.unsubscribe_button[#]</a></p>
</td>
</tr>
</table>
</body>
</html>

159
package-lock.json generated
View File

@@ -14,7 +14,6 @@
"@uppy/core": "^5.2.0",
"@uppy/xhr-upload": "^5.2.0",
"autosize": "^6.0.1",
"copy-webpack-plugin": "^14.0.0",
"css-loader": "^7.1.2",
"maplibre-gl": "^5.4.0",
"sass": "^1.97.2",
@@ -1618,6 +1617,7 @@
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
@@ -1639,6 +1639,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -1648,6 +1649,7 @@
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
@@ -1664,6 +1666,7 @@
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -2098,6 +2101,7 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@types/geojson": {
@@ -2110,12 +2114,14 @@
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz",
"integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"undici-types": ">=7.24.0 <7.24.7"
@@ -2299,6 +2305,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
@@ -2309,24 +2316,28 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
@@ -2338,12 +2349,14 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -2356,6 +2369,7 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
@@ -2365,6 +2379,7 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@xtuc/long": "4.2.2"
@@ -2374,12 +2389,14 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -2396,6 +2413,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -2409,6 +2427,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -2421,6 +2440,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -2435,6 +2455,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -2445,18 +2466,21 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"devOptional": true,
"license": "BSD-3-Clause"
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"devOptional": true,
"license": "Apache-2.0"
},
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"devOptional": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -2469,6 +2493,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10.13.0"
@@ -2481,6 +2506,7 @@
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
@@ -2497,6 +2523,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
@@ -2514,6 +2541,7 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
@@ -2626,6 +2654,7 @@
"version": "2.10.32",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz",
"integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.cjs"
@@ -2647,6 +2676,7 @@
"version": "4.28.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
"devOptional": true,
"funding": [
{
"type": "opencollective",
@@ -2680,12 +2710,14 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/caniuse-lite": {
"version": "1.0.30001793",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
"integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
"devOptional": true,
"funding": [
{
"type": "opencollective",
@@ -2738,6 +2770,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6.0"
@@ -2782,6 +2815,7 @@
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/convert-source-map": {
@@ -2791,29 +2825,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/copy-webpack-plugin": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-14.0.0.tgz",
"integrity": "sha512-3JLW90aBGeaTLpM7mYQKpnVdgsUZRExY55giiZgLuX/xTQRUs1dOCwbBnWnvY6Q6rfZoXMNwzOQJCSZPppfqXA==",
"license": "MIT",
"dependencies": {
"glob-parent": "^6.0.1",
"normalize-path": "^3.0.0",
"schema-utils": "^4.2.0",
"serialize-javascript": "^7.0.3",
"tinyglobby": "^0.2.12"
},
"engines": {
"node": ">= 20.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.1.0"
}
},
"node_modules/core-js-compat": {
"version": "3.49.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz",
@@ -2946,6 +2957,7 @@
"version": "1.5.362",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.362.tgz",
"integrity": "sha512-PUY2DrLvkjkUuWqq+KPL2iWshrJsZOcIojzRQ7eXFacc9dWga7MGMJAa15VbiejSZB1PAXaRLAiKgruHP8LB1w==",
"devOptional": true,
"license": "ISC"
},
"node_modules/emojis-list": {
@@ -2961,6 +2973,7 @@
"version": "5.22.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz",
"integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
@@ -3009,12 +3022,14 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
"integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -3024,6 +3039,7 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"devOptional": true,
"license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
@@ -3037,6 +3053,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"devOptional": true,
"license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
@@ -3049,6 +3066,7 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"devOptional": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
@@ -3058,6 +3076,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"devOptional": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
@@ -3083,6 +3102,7 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.8.x"
@@ -3092,12 +3112,14 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"devOptional": true,
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
"devOptional": true,
"funding": [
{
"type": "github",
@@ -3120,23 +3142,6 @@
"node": ">= 4.9.1"
}
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -3206,34 +3211,25 @@
"integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==",
"license": "MIT"
},
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"devOptional": true,
"license": "BSD-2-Clause"
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"devOptional": true,
"license": "ISC"
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3328,6 +3324,7 @@
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=0.10.0"
}
@@ -3337,6 +3334,7 @@
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"license": "MIT",
"optional": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -3390,6 +3388,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
@@ -3404,6 +3403,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
@@ -3439,6 +3439,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"devOptional": true,
"license": "MIT"
},
"node_modules/json-stringify-pretty-compact": {
@@ -3493,6 +3494,7 @@
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz",
"integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6.11.5"
@@ -3620,12 +3622,14 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"devOptional": true,
"license": "MIT"
},
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -3690,6 +3694,7 @@
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/node-addon-api": {
@@ -3703,20 +3708,12 @@
"version": "2.0.46",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
"integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -3826,6 +3823,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=12"
},
@@ -4142,6 +4140,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4267,6 +4266,7 @@
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
@@ -4292,15 +4292,6 @@
"semver": "bin/semver.js"
}
},
"node_modules/serialize-javascript": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz",
"integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
@@ -4390,6 +4381,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"devOptional": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -4408,6 +4400,7 @@
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
@@ -4463,6 +4456,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -4476,6 +4470,7 @@
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz",
"integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==",
"devOptional": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
@@ -4494,6 +4489,7 @@
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz",
"integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
@@ -4550,22 +4546,6 @@
}
}
},
"node_modules/tinyglobby": {
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinyqueue": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
@@ -4576,6 +4556,7 @@
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"devOptional": true,
"license": "MIT"
},
"node_modules/unicode-canonical-property-names-ecmascript": {
@@ -4636,6 +4617,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"devOptional": true,
"funding": [
{
"type": "opencollective",
@@ -4732,6 +4714,7 @@
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
"integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"glob-to-regexp": "^0.4.1",
@@ -4745,6 +4728,7 @@
"version": "5.107.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz",
"integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.8",
@@ -4864,6 +4848,7 @@
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz",
"integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10.13.0"

View File

@@ -26,7 +26,6 @@
"@uppy/core": "^5.2.0",
"@uppy/xhr-upload": "^5.2.0",
"autosize": "^6.0.1",
"copy-webpack-plugin": "^14.0.0",
"css-loader": "^7.1.2",
"maplibre-gl": "^5.4.0",
"sass": "^1.97.2",

7
public/index.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
require __DIR__.'/../vendor/autoload.php';
use Franzz\Spot\Controller;
echo (new Controller())->handle(__FILE__, $argv ?? array());

View File

@@ -3,7 +3,7 @@
## Dependencies
* npm 18+
* npm 24+
* composer
* php-mbstring
* php-imagick
@@ -25,14 +25,18 @@
## Getting started
1. Clone Git onto web server
2. composer install
3. npm install webpack
4. npm run dev
5. Update php.ini parameters
6. Copy timezone data: mariadb-tzinfo-to-sql /usr/share/zoneinfo | mariadb -u root mysql
7. Copy settings-sample.php to settings.php and populate
2. Update php.ini parameters
3. Copy timezone data: mariadb-tzinfo-to-sql /usr/share/zoneinfo | mariadb -u root mysql
4. Copy settings-sample.php to settings.php and populate
5. Follow CI/CD script in .gitea/workflows/deploy.yml
8. Go to #admin and create a new project, feed & maps
9. Add a GPX file named <project_codename>.gpx to /geo/
9. Add a GPX file named <project_codename>.gpx to /resources/geo/
## Web Root
The web server should serve `public/` as the application document root. PHP source, configuration, Composer dependencies, uploaded files, and GPX data stay outside the public tree; `public/index.php` is the front controller and webpack writes generated frontend assets to `public/assets/`.
Runtime data is exposed through symlinks only: `public/files -> ../files` and `public/geo -> ../resources/geo`. The build must not copy uploaded media or GPX data into `public/`.
## Local Development

View File

@@ -8,7 +8,7 @@
<span style="color: transparent; display: none !important; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">[#]lang:email.confirmation.preheader[#]</span>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="width:100%;max-width:600px;">
<tr>
<td width="20%"><img src="[#]local_server[#]images/icons/mstile-144x144.png" width="90%" border="0" alt="logo" /></td>
<td width="20%"><img src="[#]local_server[#]assets/images/icons/favicon-96x96.png" width="90%" border="0" alt="logo" /></td>
<td><h1>[#]lang:email.confirmation.thanks_subject[#]</h1></td>
</tr>
<tr>

View File

@@ -8,7 +8,7 @@
<span style="color: transparent; display: none !important; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">[#]lang:email.update.preheader[#]</span>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="width:100%;max-width:600px;">
<tr>
<td width="20%"><img src="[#]local_server[#]images/icons/mstile-144x144.png" width="90%" border="0" alt="logo" /></td>
<td width="20%"><img src="[#]local_server[#]assets/images/icons/favicon-96x96.png" width="90%" border="0" alt="logo" /></td>
<td><h1>[#]lang:email.update.title[#] [#]type[#] #[#]displayed_id[#]</h1></td>
</tr>
<tr>

View File

@@ -8,14 +8,14 @@
<meta property="og:description" content="[#]lang:meta.page_og_desc[#]" />
<meta property="og:type" content="website" />
<meta property="og:url" content="[#]server[#]" />
<meta property="og:image" content="images/icons/ogp.svg?v=20260528" />
<meta property="og:image" content="assets/images/icons/ogp.svg?v=20260528" />
<meta property="og:locale" content="[#]lang:meta.locale[#]" />
<link rel="icon" type="image/png" href="images/icons/favicon-96x96.png?v=20260528" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="images/icons/favicon.svg?v=20260528" />
<link rel="shortcut icon" href="images/icons/favicon.ico?v=20260528" />
<link rel="apple-touch-icon" sizes="180x180" href="images/icons/apple-touch-icon.png?v=20260528" />
<link rel="icon" type="image/png" href="assets/images/icons/favicon-96x96.png?v=20260528" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="assets/images/icons/favicon.svg?v=20260528" />
<link rel="shortcut icon" href="assets/images/icons/favicon.ico?v=20260528" />
<link rel="apple-touch-icon" sizes="180x180" href="assets/images/icons/apple-touch-icon.png?v=20260528" />
<meta name="apple-mobile-web-app-title" content="[#]title[#]" />
<link rel="manifest" href="images/icons/site.webmanifest?v=20260528" />
<link rel="manifest" href="assets/images/icons/site.webmanifest?v=20260528" />
<meta name="theme-color" content="#081B19">
<script id="app-config" type="application/json">[#]app_config[#]</script>
<title>[#]title[#]</title>

View File

@@ -6,7 +6,7 @@ import User from '@scripts/user';
import { createApp, reactive } from 'vue';
//Main template
import Spot from './Spot';
import App from './App';
//Style
import Css from '@styles/spot';
@@ -28,10 +28,10 @@ const oApi = new Api({
});
//Mount app
const oSpot = createApp(Spot);
oSpot.provide('appConfig', appConfig);
oSpot.provide('api', oApi);
oSpot.provide('lang', oLang);
oSpot.provide('projects', oProjects);
oSpot.provide('user', oUser);
oSpot.mount('#container');
const oApp = createApp(App);
oApp.provide('appConfig', appConfig);
oApp.provide('api', oApi);
oApp.provide('lang', oLang);
oApp.provide('projects', oProjects);
oApp.provide('user', oUser);
oApp.mount('#container');

View File

@@ -116,7 +116,8 @@ export default {
this.mapInitializing = false;
},
quit() {
this.lightbox.end();
this.lightbox.end(true);
this.lightbox = null;
this.removeMap();
},
async initOverview() {

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="240" height="240" overflow="hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<svg width="240" height="240" viewBox="0 0 240 240" overflow="hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>LiveTrail</title>
<g transform="translate(-494.84 -161.68)">
<g transform="translate(9.9388)">

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -3,13 +3,13 @@
"short_name": "LiveTrail",
"icons": [
{
"src": "/images/icons/web-app-manifest-192x192.png?v=20260528",
"src": "/assets/images/icons/web-app-manifest-192x192.png?v=20260528",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/images/icons/web-app-manifest-512x512.png?v=20260528",
"src": "/assets/images/icons/web-app-manifest-512x512.png?v=20260528",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="394.17" height="113.24" overflow="hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<svg width="394.17" height="113.24" overflow="hidden" version="1.1" viewBox="0 0 394.17 113.24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>LiveTrail</title>
<g transform="translate(-417.76 -414.44)">
<g transform="translate(0 .3998)">
<path d="m501.57 514.18h-5.1953v12.822h-1.9336v-12.822h-5.1953v-1.7188h12.324zm13.076 12.822h-1.9336v-7.1191h-7.2559v7.1191h-1.9336v-14.541h1.9336v5.7031h7.2559v-5.7031h1.9336zm13.486 0h-9.5801v-14.541h9.5801v1.7188h-7.6465v3.9844h7.6465v1.7188h-7.6465v5.4004h7.6465zm15.098 0h-2.5098l-4.8633-5.7812h-2.7246v5.7812h-1.9336v-14.541h4.0723q1.3184 0 2.1973 0.17579 0.87891 0.16601 1.582 0.60546 0.79101 0.49805 1.2305 1.2598 0.44922 0.75195 0.44922 1.9141 0 1.5723-0.79101 2.6367-0.79102 1.0547-2.1777 1.5918zm-4.5215-10.449q0-0.625-0.22461-1.1035-0.21484-0.48829-0.72266-0.82032-0.41992-0.2832-0.99609-0.39062-0.57617-0.11719-1.3574-0.11719h-2.2754v5.4883h1.9531q0.91797 0 1.6016-0.15625 0.6836-0.16601 1.1621-0.60547 0.43946-0.41015 0.64454-0.9375 0.21484-0.53711 0.21484-1.3574zm15.977 10.449h-9.5801v-14.541h9.5801v1.7188h-7.6465v3.9844h7.6465v1.7188h-7.6465v5.4004h7.6465zm21.562 0h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm17.383 5.7129h-2.3926l-6.8945-13.008v13.008h-1.8066v-14.541h2.998l6.2891 11.875v-11.875h1.8066zm16.152-7.2559q0 1.9824-0.86914 3.5938-0.85938 1.6113-2.2949 2.5-0.99609 0.61523-2.2266 0.88867-1.2207 0.27344-3.2226 0.27344h-3.6719v-14.541h3.6328q2.1289 0 3.3789 0.3125 1.2598 0.30274 2.1289 0.83985 1.4844 0.92773 2.3144 2.4707t0.83008 3.6621zm-2.0215-0.0293q0-1.709-0.5957-2.8809-0.5957-1.1719-1.7773-1.8457-0.85938-0.48828-1.8262-0.67383-0.96679-0.19531-2.3144-0.19531h-1.8164v11.221h1.8164q1.3965 0 2.4316-0.20507 1.0449-0.20508 1.9141-0.76172 1.084-0.69336 1.6211-1.8262 0.54687-1.1328 0.54687-2.832zm23.145 2.8125q0 1.084-0.41015 1.9141-0.41016 0.83007-1.1035 1.3672-0.82031 0.64453-1.8066 0.91797-0.97656 0.27344-2.4902 0.27344h-5.1562v-14.541h4.3066q1.5918 0 2.3828 0.11719t1.5137 0.48828q0.80078 0.41992 1.1621 1.084 0.36133 0.65429 0.36133 1.5723 0 1.0352-0.52734 1.7676-0.52735 0.72266-1.4062 1.1621v0.0781q1.4746 0.30273 2.3242 1.2988 0.84961 0.98633 0.84961 2.5zm-3.252-6.5527q0-0.52734-0.17578-0.88867t-0.56641-0.58594q-0.45898-0.26367-1.1133-0.32227-0.6543-0.0684-1.6211-0.0684h-2.3047v4.1992h2.5q0.9082 0 1.4453-0.0879 0.53711-0.0976 0.9961-0.39062 0.45898-0.29297 0.64453-0.75196 0.19531-0.46875 0.19531-1.1035zm1.2402 6.6309q0-0.87891-0.26367-1.3965-0.26367-0.51757-0.95703-0.8789-0.46875-0.24414-1.1426-0.3125-0.66406-0.0781-1.6211-0.0781h-3.0371v5.4102h2.5586q1.2695 0 2.0801-0.12695 0.81055-0.13672 1.3281-0.48829 0.54687-0.38085 0.80078-0.86914 0.2539-0.48828 0.2539-1.2598zm16.221 4.3945h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm17.52 4.6582q-0.53711 0.23438-0.97656 0.43946-0.42969 0.20507-1.1328 0.42968-0.5957 0.18555-1.2988 0.3125-0.69335 0.13672-1.5332 0.13672-1.582 0-2.8809-0.43945-1.2891-0.44922-2.2461-1.3965-0.9375-0.92773-1.4648-2.3535-0.52734-1.4356-0.52734-3.3301 0-1.7969 0.50781-3.2129 0.50782-1.416 1.4648-2.3926 0.92773-0.94726 2.2363-1.4453 1.3184-0.49805 2.9199-0.49805 1.1719 0 2.334 0.28321 1.1719 0.2832 2.5977 0.99609v2.2949h-0.14649q-1.2012-1.0059-2.3828-1.4648-1.1816-0.45899-2.5293-0.45899-1.1035 0-1.9922 0.36133-0.87891 0.35156-1.5723 1.1035-0.67383 0.73242-1.0547 1.8555-0.37109 1.1133-0.37109 2.5781 0 1.5332 0.41016 2.6367 0.41992 1.1035 1.0742 1.7969 0.6836 0.72266 1.5918 1.0742 0.91797 0.3418 1.9336 0.3418 1.3965 0 2.6172-0.47852 1.2207-0.47851 2.2852-1.4355h0.13672zm14.424 1.0547h-2.5098l-5.752-6.4746-1.4453 1.543v4.9316h-1.9336v-14.541h1.9336v7.5879l7.0606-7.5879h2.3438l-6.4941 6.8359zm20.664 0h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm18.418 4.6387q-1.1914 0.54688-2.6074 0.95703-1.4062 0.40039-2.7246 0.40039-1.6992 0-3.1152-0.46875t-2.4121-1.4062q-1.0059-0.94726-1.5527-2.3633-0.54688-1.4258-0.54688-3.3301 0-3.4863 2.0312-5.498 2.041-2.0215 5.5957-2.0215 1.2402 0 2.5293 0.30274 1.2988 0.29297 2.793 1.0059v2.2949h-0.17578q-0.30274-0.23438-0.87891-0.61524t-1.1328-0.63476q-0.67383-0.30274-1.5332-0.49805-0.84961-0.20508-1.9336-0.20508-2.4414 0-3.8672 1.5723-1.416 1.5625-1.416 4.2383 0 2.8223 1.4844 4.3945 1.4844 1.5625 4.043 1.5625 0.9375 0 1.8652-0.18555 0.9375-0.18554 1.6406-0.47851v-3.5644h-3.8965v-1.6992h5.8106zm14.844 1.0742h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm11.416 5.7129h-5.7422v-1.4844h1.9043v-11.572h-1.9043v-1.4844h5.7422v1.4844h-1.9043v11.572h1.9043zm14.385 0h-2.3926l-6.8945-13.008v13.008h-1.8066v-14.541h2.998l6.2891 11.875v-11.875h1.8066z" fill="#335918" aria-label="THERE AND BACK AGAIN"/>
<path d="m501.57 514.18h-5.1953v12.822h-1.9336v-12.822h-5.1953v-1.7188h12.324zm13.076 12.822h-1.9336v-7.1191h-7.2559v7.1191h-1.9336v-14.541h1.9336v5.7031h7.2559v-5.7031h1.9336zm13.486 0h-9.5801v-14.541h9.5801v1.7188h-7.6465v3.9844h7.6465v1.7188h-7.6465v5.4004h7.6465zm15.098 0h-2.5098l-4.8633-5.7812h-2.7246v5.7812h-1.9336v-14.541h4.0723q1.3184 0 2.1973 0.17579 0.87891 0.16601 1.582 0.60546 0.79101 0.49805 1.2305 1.2598 0.44922 0.75195 0.44922 1.9141 0 1.5723-0.79101 2.6367-0.79102 1.0547-2.1777 1.5918zm-4.5215-10.449q0-0.625-0.22461-1.1035-0.21484-0.48829-0.72266-0.82032-0.41992-0.2832-0.99609-0.39062-0.57617-0.11719-1.3574-0.11719h-2.2754v5.4883h1.9531q0.91797 0 1.6016-0.15625 0.6836-0.16601 1.1621-0.60547 0.43946-0.41015 0.64454-0.9375 0.21484-0.53711 0.21484-1.3574zm15.977 10.449h-9.5801v-14.541h9.5801v1.7188h-7.6465v3.9844h7.6465v1.7188h-7.6465v5.4004h7.6465zm21.562 0h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm17.383 5.7129h-2.3926l-6.8945-13.008v13.008h-1.8066v-14.541h2.998l6.2891 11.875v-11.875h1.8066zm16.152-7.2559q0 1.9824-0.86914 3.5938-0.85938 1.6113-2.2949 2.5-0.99609 0.61523-2.2266 0.88867-1.2207 0.27344-3.2226 0.27344h-3.6719v-14.541h3.6328q2.1289 0 3.3789 0.3125 1.2598 0.30274 2.1289 0.83985 1.4844 0.92773 2.3144 2.4707t0.83008 3.6621zm-2.0215-0.0293q0-1.709-0.5957-2.8809t-1.7773-1.8457q-0.85938-0.48828-1.8262-0.67383-0.96679-0.19531-2.3144-0.19531h-1.8164v11.221h1.8164q1.3965 0 2.4316-0.20507 1.0449-0.20508 1.9141-0.76172 1.084-0.69336 1.6211-1.8262 0.54687-1.1328 0.54687-2.832zm23.145 2.8125q0 1.084-0.41015 1.9141-0.41016 0.83007-1.1035 1.3672-0.82031 0.64453-1.8066 0.91797-0.97656 0.27344-2.4902 0.27344h-5.1562v-14.541h4.3066q1.5918 0 2.3828 0.11719t1.5137 0.48828q0.80078 0.41992 1.1621 1.084 0.36133 0.65429 0.36133 1.5723 0 1.0352-0.52734 1.7676-0.52735 0.72266-1.4062 1.1621v0.0781q1.4746 0.30273 2.3242 1.2988 0.84961 0.98633 0.84961 2.5zm-3.252-6.5527q0-0.52734-0.17578-0.88867t-0.56641-0.58594q-0.45898-0.26367-1.1133-0.32227-0.6543-0.0684-1.6211-0.0684h-2.3047v4.1992h2.5q0.9082 0 1.4453-0.0879 0.53711-0.0976 0.9961-0.39062 0.45898-0.29297 0.64453-0.75196 0.19531-0.46875 0.19531-1.1035zm1.2402 6.6309q0-0.87891-0.26367-1.3965-0.26367-0.51757-0.95703-0.8789-0.46875-0.24414-1.1426-0.3125-0.66406-0.0781-1.6211-0.0781h-3.0371v5.4102h2.5586q1.2695 0 2.0801-0.12695 0.81055-0.13672 1.3281-0.48829 0.54687-0.38085 0.80078-0.86914 0.2539-0.48828 0.2539-1.2598zm16.221 4.3945h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm17.52 4.6582q-0.53711 0.23438-0.97656 0.43946-0.42969 0.20507-1.1328 0.42968-0.5957 0.18555-1.2988 0.3125-0.69335 0.13672-1.5332 0.13672-1.582 0-2.8809-0.43945-1.2891-0.44922-2.2461-1.3965-0.9375-0.92773-1.4648-2.3535-0.52734-1.4356-0.52734-3.3301 0-1.7969 0.50781-3.2129 0.50782-1.416 1.4648-2.3926 0.92773-0.94726 2.2363-1.4453 1.3184-0.49805 2.9199-0.49805 1.1719 0 2.334 0.28321 1.1719 0.2832 2.5977 0.99609v2.2949h-0.14649q-1.2012-1.0059-2.3828-1.4648-1.1816-0.45899-2.5293-0.45899-1.1035 0-1.9922 0.36133-0.87891 0.35156-1.5723 1.1035-0.67383 0.73242-1.0547 1.8555-0.37109 1.1133-0.37109 2.5781 0 1.5332 0.41016 2.6367 0.41992 1.1035 1.0742 1.7969 0.6836 0.72266 1.5918 1.0742 0.91797 0.3418 1.9336 0.3418 1.3965 0 2.6172-0.47852 1.2207-0.47851 2.2852-1.4355h0.13672zm14.424 1.0547h-2.5098l-5.752-6.4746-1.4453 1.543v4.9316h-1.9336v-14.541h1.9336v7.5879l7.0606-7.5879h2.3438l-6.4941 6.8359zm20.664 0h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm18.418 4.6387q-1.1914 0.54688-2.6074 0.95703-1.4062 0.40039-2.7246 0.40039-1.6992 0-3.1152-0.46875t-2.4121-1.4062q-1.0059-0.94726-1.5527-2.3633-0.54688-1.4258-0.54688-3.3301 0-3.4863 2.0312-5.498 2.041-2.0215 5.5957-2.0215 1.2402 0 2.5293 0.30274 1.2988 0.29297 2.793 1.0059v2.2949h-0.17578q-0.30274-0.23438-0.87891-0.61524t-1.1328-0.63476q-0.67383-0.30274-1.5332-0.49805-0.84961-0.20508-1.9336-0.20508-2.4414 0-3.8672 1.5723-1.416 1.5625-1.416 4.2383 0 2.8223 1.4844 4.3945 1.4844 1.5625 4.043 1.5625 0.9375 0 1.8652-0.18555 0.9375-0.18554 1.6406-0.47851v-3.5644h-3.8965v-1.6992h5.8106zm14.844 1.0742h-2.0606l-1.4258-4.0527h-6.2891l-1.4258 4.0527h-1.9629l5.293-14.541h2.5781zm-4.082-5.7129-2.5488-7.1387-2.5586 7.1387zm11.416 5.7129h-5.7422v-1.4844h1.9043v-11.572h-1.9043v-1.4844h5.7422v1.4844h-1.9043v11.572h1.9043zm14.385 0h-2.3926l-6.8945-13.008v13.008h-1.8066v-14.541h2.998l6.2891 11.875v-11.875h1.8066z" fill="#335918" aria-label="THERE AND BACK AGAIN"/>
<path d="m417.76 519.74h52.865" fill="none" fill-rule="evenodd" stroke="#335918" stroke-miterlimit="8" stroke-width="2.1593"/>
<path d="m759.07 519.74h52.865" fill="none" fill-rule="evenodd" stroke="#335918" stroke-miterlimit="8" stroke-width="2.1593"/>
<path d="m462.24 492.87h-44.479v-74.688h16.823v61.042h27.656zm16.771-61.771q-4.1667 0-6.8229-2.4479-2.6563-2.5-2.6563-6.0938 0-3.6979 2.6563-6.0417 2.6562-2.3438 6.8229-2.3438 4.2188 0 6.8229 2.3438 2.6563 2.3438 2.6563 6.0417 0 3.75-2.6563 6.1458-2.6042 2.3958-6.8229 2.3958zm8.125 61.771h-16.458v-53.334h16.458zm64.636-53.334-19.844 53.334h-18.75l-18.906-53.334h17.604l9.2709 32.865q1.5625 5.5729 1.8229 9.4792h0.20833q0.36458-3.6979 1.9271-9.1667l9.4792-33.177zm53.906 31.354h-34.792q0.83333 11.615 14.635 11.615 8.8021 0 15.469-4.1667v11.875q-7.3959 3.9584-19.219 3.9584-12.917 0-20.052-7.1354-7.1354-7.1875-7.1354-20 0-13.281 7.7084-21.042 7.7084-7.7604 18.958-7.7604 11.667 0 18.021 6.9271 6.4063 6.9271 6.4063 18.802zm-15.26-10.104q0-11.458-9.2709-11.458-3.9583 0-6.875 3.2813-2.8646 3.2813-3.4896 8.1771z" fill="#335918" aria-label="Live"/>
<path d="m664.9 432.01h-21.302v60.99h-16.875v-60.99h-21.198v-13.698h59.375zm35.208 22.5q-2.9688-1.6146-6.9271-1.6146-5.3646 0-8.3854 3.9583-3.0208 3.9063-3.0208 10.677v25.469h-16.458v-53.334h16.458v9.8959h0.20833q3.9063-10.833 14.063-10.833 2.6042 0 4.0625 0.625zm52.031 38.49h-15.573v-7.6563h-0.20833q-5.3646 8.9584-15.885 8.9584-7.7604 0-12.24-4.375-4.4271-4.4271-4.4271-11.771 0-15.521 18.385-17.917l14.479-1.9271q0-8.75-9.4792-8.75-9.5313 0-18.125 5.6771v-12.396q3.4375-1.7708 9.375-3.125 5.9896-1.3542 10.885-1.3542 22.813 0 22.813 22.76zm-15.469-21.667v-3.5938l-9.6875 1.25q-8.0209 1.0417-8.0209 7.2396 0 2.8125 1.9271 4.6354 1.9792 1.7708 5.3125 1.7708 4.6354 0 7.5521-3.1771 2.9167-3.2292 2.9167-8.125zm36.823-40.104q-4.1667 0-6.8229-2.4479-2.6563-2.5-2.6563-6.0938 0-3.6979 2.6563-6.0417 2.6563-2.3438 6.8229-2.3438 4.2188 0 6.8229 2.3438 2.6563 2.3438 2.6563 6.0417 0 3.75-2.6563 6.1458-2.6042 2.3958-6.8229 2.3958zm8.125 61.771h-16.458v-53.334h16.458zm30.313 0h-16.458v-78.959h16.458z" fill="#11db6d" aria-label="Trail"/>
<path d="m664.9 432.01h-21.302v60.99h-16.875v-60.99h-21.198v-13.698h59.375zm35.208 22.5q-2.9688-1.6146-6.9271-1.6146-5.3646 0-8.3854 3.9583-3.0208 3.9063-3.0208 10.677v25.469h-16.458v-53.334h16.458v9.8959h0.20833q3.9063-10.833 14.063-10.833 2.6042 0 4.0625 0.625zm52.031 38.49h-15.573v-7.6563h-0.20833q-5.3646 8.9584-15.885 8.9584-7.7604 0-12.24-4.375-4.4271-4.4271-4.4271-11.771 0-15.521 18.385-17.917l14.479-1.9271q0-8.75-9.4792-8.75-9.5313 0-18.125 5.6771v-12.396q3.4375-1.7708 9.375-3.125 5.9896-1.3542 10.885-1.3542 22.813 0 22.813 22.76zm-15.469-21.667v-3.5938l-9.6875 1.25q-8.0209 1.0417-8.0209 7.2396 0 2.8125 1.9271 4.6354 1.9792 1.7708 5.3125 1.7708 4.6354 0 7.5521-3.1771 2.9167-3.2292 2.9167-8.125zm36.823-40.104q-4.1667 0-6.8229-2.4479-2.6563-2.5-2.6563-6.0938 0-3.6979 2.6563-6.0417t6.8229-2.3438q4.2188 0 6.8229 2.3438 2.6563 2.3438 2.6563 6.0417 0 3.75-2.6563 6.1458-2.6042 2.3958-6.8229 2.3958zm8.125 61.771h-16.458v-53.334h16.458zm30.313 0h-16.458v-78.959h16.458z" fill="#11db6d" aria-label="Trail"/>
</g>
</g>
<metadata>

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -1,47 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
<title>[#]lang:email.update.subject[#]</title>
</head>
<body>
<span style="color: transparent; display: none !important; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">[#]lang:email.update.preheader[#]</span>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="width:100%;max-width:600px;">
<tr>
<td width="20%"><img src="[#]local_server[#]images/icons/mstile-144x144.png" width="90%" border="0" alt="logo" /></td>
<td><h1>[#]lang:email.update.title[#] [#]type[#] #[#]displayed_id[#]</h1></td>
</tr>
<tr>
<td colspan="2">
<div style="background-color:#6dff58;color:#326526;border-radius:3px;padding:1rem;margin-top:1rem;display:inline-block;box-shadow: 2px 2px 3px 0px rgba(0,0,0,.5);">
<a href="[#]local_server[#]" target="_blank" rel="noopener"><img style="border-radius:3px;" src="[#]marker_img_url[#]" alt="position" /></a>
<br />[#]lat_dms[#] [#]lon_dms[#]
<br />[#]date_time[#] ([#]timezone[#])
</div>
</td>
</tr>
<tr>
<td colspan="2">
<h2>[#]lang:email.update.latest_news[#]</h2>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<!-- [PART] news [START] -->
<tr>
<td>
<a href="[#]local_server[#]#project-[#]project[#]-[#]type[#]-[#]id[#]" target="_blank" rel="noopener" style="text-decoration:none;background-color:#EEE;color:#333;margin-bottom:1rem;border-radius:3px;padding:5%;display:inline-block;width:90%;box-shadow: 2px 2px 3px 0px rgba(0,0,0,.5);">
<!-- [PART] media [START] --><img src="[#]local_server[#][#]thumb_path[#]" style="max-height:200px;image-orientation:from-image;" /><br /><span>[#]comment[#]</span><!-- [PART] media [END] -->
<!-- [PART] post [START] --><span>[#]content[#]</span><br /><span style="margin-top:0.5em;float:right;">--[#]formatted_name[#]</span><!-- [PART] post [END] -->
</a>
</td>
</tr>
<!-- [PART] news [END] -->
</table>
</td>
</tr>
<tr>
<td colspan="2">
<p>[#]lang:email.unsubscribe[#] <a href="[#]unsubscribe_link[#]" target="_blank" rel="noopener">[#]lang:email.unsubscribe_button[#]</a></p>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -54,6 +54,10 @@ export default class Lightbox {
document.body.addEventListener('click', this.boundOnBodyClick);
}
disable() {
document.body.removeEventListener('click', this.boundOnBodyClick);
}
onBodyClick(event) {
const link = event.target.closest('a[data-lightbox], area[data-lightbox]');
if (!link) return;
@@ -597,17 +601,28 @@ export default class Lightbox {
}
}
end() {
end(dispose = false) {
this.disableKeyboardNav();
this.video?.pause();
this.video?.removeAttribute('src');
this.container.classList.remove('lb-video-nav', 'moveable', 'moving');
this.container?.classList.remove('lb-video-nav', 'moveable', 'moving');
window.removeEventListener('resize', this.boundOnResize);
window.removeEventListener('mousemove', this.boundOnDragMove);
if(dispose){
this.disable();
if(this.resizeTimer) clearTimeout(this.resizeTimer);
window.removeEventListener('mouseup', this.boundOnDragEnd);
this.lightbox?.remove();
this.overlay?.remove();
this.album = [];
}
else {
this.fade(this.lightbox, false, this.options.fadeDuration);
this.fade(this.overlay, false, this.options.fadeDuration);
if (this.options.disableScrolling) document.body.classList.remove('lb-disable-scrolling');
this.options.onClosing();
}
if (this.options.disableScrolling) document.body.classList.remove('lb-disable-scrolling');
}
}

View File

@@ -120,13 +120,13 @@ input, textarea, button, a.button {
h1 {
font-size: 2em;
font-weight: bold;
margin: var.$block-spacing 0 0 var.$elem-spacing;
margin: var.$block-spacing 0 var.$elem-spacing;
}
h2 {
font-size: 1.2em;
font-weight: bold;
margin: var.$block-spacing 0 0 var.$elem-spacing;
margin: var.$block-spacing 0 var.$elem-spacing;
}
/* Feedback */

View File

@@ -28,13 +28,19 @@
url(../images/logo_bg.webp)
50% 50%;
.logo-icon {
img {
display: block;
flex: 0 0 auto;
height: auto;
max-width: 100%;
object-fit: contain;
&.logo-icon {
width: 40%;
height: auto;
}
.logo-title {
&.logo-title {
width: 70%;
height: auto;
}
}
.last_update {