Compare commits
No commits in common. "Production" and "master" have entirely different histories.
Production
...
master
18
.editorconfig
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[docker-compose.yml]
|
||||||
|
indent_size = 4
|
59
.env.example
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=laravel
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
BROADCAST_DRIVER=log
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=sync
|
||||||
|
SESSION_DRIVER=file
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=mailpit
|
||||||
|
MAIL_PORT=1025
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
PUSHER_HOST=
|
||||||
|
PUSHER_PORT=443
|
||||||
|
PUSHER_SCHEME=https
|
||||||
|
PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
|
VITE_PUSHER_HOST="${PUSHER_HOST}"
|
||||||
|
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||||
|
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
||||||
|
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
11
.gitattributes
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.blade.php diff=html
|
||||||
|
*.css diff=css
|
||||||
|
*.html diff=html
|
||||||
|
*.md diff=markdown
|
||||||
|
*.php diff=php
|
||||||
|
|
||||||
|
/.github export-ignore
|
||||||
|
CHANGELOG.md export-ignore
|
||||||
|
.styleci.yml export-ignore
|
24
.gitignore
vendored
|
@ -1,5 +1,19 @@
|
||||||
node_modules/
|
/.phpunit.cache
|
||||||
uploads/
|
/**/node_modules
|
||||||
config/default.json
|
/public/build
|
||||||
.vscode/
|
/public/hot
|
||||||
db_data/
|
/public/storage
|
||||||
|
/storage/*.key
|
||||||
|
/vendor
|
||||||
|
.env
|
||||||
|
.env.backup
|
||||||
|
.env.production
|
||||||
|
.phpunit.result.cache
|
||||||
|
Homestead.json
|
||||||
|
Homestead.yaml
|
||||||
|
auth.json
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
/.fleet
|
||||||
|
/.idea
|
||||||
|
/.vscode
|
||||||
|
|
1
.nvmrc
|
@ -1 +0,0 @@
|
||||||
v20.11.1
|
|
436
README.md
|
@ -1,371 +1,85 @@
|
||||||
# Rusco Map
|
# Rusco Map
|
||||||
|
|
||||||
_Una mappa della propria città dove utenti in anonimo possono inserire dei marker con nome, descrizione e foto dell'oggetto abbandonato, segnalandolo a tutti i visitatori della mappa._
|
Una mappa webapp con focus sulla propria città (sttando coord del index.j/setView) dove degli utenti autenticati (anche in anonimo) posso scattare una foto agli oggetti/mobili abbandonati per strada e segnalarli a tutti i visitatori della mappa.
|
||||||
<br> Sulla falsa riga del "_te lo regalo se vieni a prenderlo_", questo è più il "_segnalo che c'è sta roba lì, è tua se te la vai a prendere_"
|
|
||||||
|
|
||||||
<a href="https://ruscomap.accol.li">
|
|
||||||
<img src="screenRuscomap.png" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
### versione 0.1
|
|
||||||
|
|
||||||
- [x] Aggiungere il marker (visivo) al clic di inserimento marker [[commit f611832592](https://git.lattuga.net/scossa/ruscomap/commit/f6118325925ba91173cf5bcc0a206b85fa3ef1a3)]
|
|
||||||
- [x] Al momento si possono aggiungere infiniti marker (temporanei), da fixare [[commit 0fba9efe99](https://git.lattuga.net/scossa/ruscomap/commit/0fba9efe99057119ef5eedec078987482a193fea)]
|
|
||||||
|
|
||||||
### versione 0.2
|
|
||||||
|
|
||||||
- [x] ~~Cancellare i marker creati > di 24h (sia record db che img)~~ [[commit 78d4b6b216](https://git.lattuga.net/scossa/ruscomap/commit/78d4b6b2169d43550aa3af800ac2f946ebeb9743)]
|
|
||||||
- [x] Rimuovere pezzi di codice js per cancellare marker creati > di 24h. [[commit 971f1a0672](https://git.lattuga.net/scossa/ruscomap/commit/971f1a06725cd633da7904ae412a2e53f2afeab4)]
|
|
||||||
- [x] Scrivere script bash (<code>delete_rusco.sh</code>) che cancella tutti marker [[commit 8a5260d62f](https://git.lattuga.net/scossa/ruscomap/commit/8a5260d62f4333f4ae9c6cd1489f41481f5635f6)]
|
|
||||||
- [x] Scrivere script bash (<code>pulisci_vecchio_rusco.sh</code>) che cancella tutti marker più vecchi di 24h (automatico) [[commit 8a5260d62f](https://git.lattuga.net/scossa/ruscomap/commit/8a5260d62f4333f4ae9c6cd1489f41481f5635f6)]
|
|
||||||
- [x] Come mettere nel cron del server lo script che cancella i marker più vecchi di 24h [[commit 5dc0c22eae](https://git.lattuga.net/scossa/ruscomap/commit/5dc0c22eae2a4222f3ce8dc35a1d89df02ac836a)]
|
|
||||||
- [x] Scrivere script bash (<code>pulisci_manualmente_vecchio_rusco.sh</code>) che cancella tutti marker più vecchi di 24h (manuale) [[commit 8a5260d62f](https://git.lattuga.net/scossa/ruscomap/commit/8a5260d62f4333f4ae9c6cd1489f41481f5635f6)]
|
|
||||||
- [x] pushare e spostare script in cartella <code>/script</code> [[commit 8a5260d62f](https://git.lattuga.net/scossa/ruscomap/commit/8a5260d62f4333f4ae9c6cd1489f41481f5635f6)]
|
|
||||||
|
|
||||||
### versione 0.3
|
|
||||||
|
|
||||||
- [x] Riformattare visualizzazione form inserimento marker per mobile [[commit 9d5a7f8b71 & parents](https://git.lattuga.net/scossa/ruscomap/commit/9d5a7f8b71e0e2dd39f0addfa4a8117f62e23170)]
|
|
||||||
- [x] Milgiorare css del form inserimento dati marker [[commit 9d5a7f8b71 & parents](https://git.lattuga.net/scossa/ruscomap/commit/9d5a7f8b71e0e2dd39f0addfa4a8117f62e23170)]
|
|
||||||
|
|
||||||
### versione 0.4
|
|
||||||
|
|
||||||
- [x] Implementare il bottone in alto a dx: quando premuto per passare alla modalità inserimento diventa una _X rossa_ che se premuta annulla l'inserimento marker [[commit fa82dc221e](https://git.lattuga.net/scossa/ruscomap/commit/fa82dc221e2e8d1648c78534c0320bd099f897f0)]
|
|
||||||
- [x] A marker aggiunto con successo come icona del bottone in alto a dx rimane la X rossa (in modalità inserimento marker) invece di ritornare l'icona del marker (ovvero passare in modalità normale/visualizzazione) [[commit f9868974c6](https://git.lattuga.net/scossa/ruscomap/commit/f9868974c6b6fd5b92d8684bf5dad7687524a92d)]
|
|
||||||
- [x] Eliminare visualizzazione del marker temporaneo se viene cliccata la X rossa o aggiunto un nuovo marker (non temp) [[commit f9868974c6](https://git.lattuga.net/scossa/ruscomap/commit/f9868974c6b6fd5b92d8684bf5dad7687524a92d)]
|
|
||||||
|
|
||||||
### versione 0.5
|
|
||||||
|
|
||||||
- [x] Mostrare data/ora pubblicazione del marker per far capire al visitatore quanto tempo fa è stato avvistato il rusco [[commit c811b4eb4e](https://git.lattuga.net/scossa/ruscomap/commit/c811b4eb4e5d774eb5ccd5bceb237419105bd5d3)]
|
|
||||||
- [x] Eliminare dati e immagine da marker temporaneo (lasciare solo descrizione) [[commit 76032e6329](https://git.lattuga.net/scossa/ruscomap/commit/76032e6329936804d2dac03c3eb573b233b56f33)]
|
|
||||||
|
|
||||||
### versione 0.6
|
|
||||||
|
|
||||||
- [x] Cancellare dati file picker del form[[commit 9b8c376c53](https://git.lattuga.net/scossa/ruscomap/commit/9b8c376c53f9f52a0ae2cbfb186769a4ca1cd1e0)]
|
|
||||||
- [x] Pop-Up all'apertura di ruscomap con descrizione breve [[commit 4dac8709ca](https://git.lattuga.net/scossa/ruscomap/commit/4dac8709ca1cc8d580236ba81109a376147f749c)]
|
|
||||||
|
|
||||||
### versione 0.7
|
|
||||||
|
|
||||||
- [x] Scrivere query per funzione di ricerca [[commit 08b550ed89](https://git.lattuga.net/scossa/ruscomap/commit/08b550ed896309994f5e4a2aed762ecf5d81cfcf)]
|
|
||||||
- [x] Inserire la posizione del marker tramite il gps [[commit a57738eddc](https://git.lattuga.net/scossa/ruscomap/commit/a57738eddce46fe858c6ee88e57713ef18cf84fe)]
|
|
||||||
|
|
||||||
|
|
||||||
### versione 0.8
|
|
||||||
|
|
||||||
Commit a casa di cek [[commit 89019f168c](https://git.lattuga.net/RuscoMap/ruscomap/commit/a5ba2d24134c27634ae85f2eac2bccc636e75cbb)]<br>
|
|
||||||
- [x] L'orario di inserimento del marker risulta essere -4h prima dell'orario di inserimento reale. (nel db invece è storato con -2h rispetto orario reale) [[commit a5ba2d2413](https://git.lattuga.net/RuscoMap/ruscomap/commit/a5ba2d24134c27634ae85f2eac2bccc636e75cbb)]
|
|
||||||
- [x] per fetchare i nuovi marker ogni 5 secondi al layer marker viene aggiunto un altro layer marker, invece di cancellare il vecchio layer e caricare il nuovo. (Si nota dall'ombra dei marker sulla mappa che ogni 5 secondi aumenta di intensità) [[commit a5ba2d2413](https://git.lattuga.net/RuscoMap/ruscomap/commit/a5ba2d24134c27634ae85f2eac2bccc636e75cbb)]
|
|
||||||
|
|
||||||
|
|
||||||
### versione 0.8.5
|
|
||||||
|
|
||||||
- [ ] [bug gps] Quando si trova la propria posizione utilizzando la funzione GPS, non si riesce a inserire/cliccare sul punto in cui ci si trova finchè non si disattiva la funzione GPS
|
|
||||||
- [ ] Possibilità di poter roteare la mappa
|
|
||||||
- [ ] Mostrare immagine del rusco a tuttoschermo/ingrandita quando cliccata nel pop up
|
|
||||||
- [ ] Possibilità di linkare un particolare rusco (ruscomap che si apre con il pop up aperto di uno rusco specifico)
|
|
||||||
|
|
||||||
### versione 0.9
|
|
||||||
|
|
||||||
- [ ] Creare form login per admin
|
|
||||||
- [ ] Creare bottone per form/pagina "area riservata"/"accedi"
|
|
||||||
- [ ] Creare Pannello Admin
|
|
||||||
- [ ] Creare ruolo Admin: Visita mappa, Aggiungi marker, Accesso a pannello admin
|
|
||||||
- [ ] Gestione autenticazione utente admin con password per accesso al pannello
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## versione 1.0
|
|
||||||
|
|
||||||
- [ ] Implementare il pannelo per permettere all'admin di poter creare utenti (nomeutente/password, no mail o altro)
|
|
||||||
- [ ] Creare ruolo Utente. Permessi: Visita mappa, Aggiungi marker
|
|
||||||
- [ ] Ruolo Ospite. Permessi: Visita mappa
|
|
||||||
- [ ] Gestione autenticazione utenti con password
|
|
||||||
- [ ] Implemtare nel pannello lo switch per on/off inserimento solo utenti e admin o anche ospiti.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### versione 1.1
|
|
||||||
|
|
||||||
- [ ] Feature da pannello admin: poter cancellare un utente
|
|
||||||
|
|
||||||
### versione 1.2
|
|
||||||
|
|
||||||
- [ ] Feature da pannello admin: poter disabilitare un utente
|
|
||||||
|
|
||||||
### versione 1.3
|
|
||||||
|
|
||||||
- [ ] Cancella Marker
|
|
||||||
- [ ] Quando autenticati come admin mostrare un pulsante affianco/sopra/dentro al form dei dati del marker che ha la funzione di cancellare il marker corrispondente
|
|
||||||
- [ ] Popup che chiede la conferma della cancellazione del marker
|
|
||||||
- [ ] Dare permessi di cancellazione marker all'admin
|
|
||||||
|
|
||||||
### ToDo er versione 1.4
|
|
||||||
|
|
||||||
- [ ] Creare form per ricercare tra i titoli/descrizioni dei marker esistenti (query esempio: "divano", scompaiono tutti i marker e rimangono solo quelli che nel nome o descrizione hanno "divano")
|
|
||||||
|
|
||||||
### versione 1.5
|
|
||||||
|
|
||||||
- [ ] Creare Ruolo Moderatore. Permessi : Visita mappa, Aggiungi marker, Cancella marker
|
|
||||||
|
|
||||||
### versione 1.6
|
|
||||||
|
|
||||||
- [ ] Feature da pannello admin: poter cambiare ruolo a un utente (utente <---> moderatore)
|
|
||||||
|
|
||||||
### versione 1.7
|
|
||||||
|
|
||||||
- [ ] Feature da pannello admin: poter settare permessi personalizzati ai vari Ruoli (magari si vuole dare l'inserimento anche agli ospiti e/o la cancellazione dei marker agli user)
|
|
||||||
|
|
||||||
### versione 1.8
|
|
||||||
|
|
||||||
- [ ] Creare form registrazione con mail
|
|
||||||
- [ ] Richiedere conferma mail via link spedito a l'indirizzo
|
|
||||||
|
|
||||||
## versione 2.0
|
|
||||||
|
|
||||||
- [ ] Implementare ActivityPub
|
|
||||||
|
|
||||||
## Possibili altre implementazioni possibili in qualsiasi momento
|
|
||||||
|
|
||||||
- [ ] Marker freschezza rusco (esempio: piu è datato il marker inserito e piu è scuro il colore del marker)
|
|
||||||
- [ ] Script di installazione ruscomap
|
|
||||||
- [ ] Fare il modo che lo script di Aggiornamento non pialli le var settate negli script di pulizia rusco
|
|
||||||
- [x] Standardizzare con le varialibili del <code>default.json</code> gli script [[commit a57738eddc](https://git.lattuga.net/scossa/ruscomap/commit/a57738eddce46fe858c6ee88e57713ef18cf84fe)]
|
|
||||||
- [x] Script per inserire i posti dove fare la ricicla a bologna (riciclabologna.vado.li) [[commit 03d7e1529b](https://git.lattuga.net/RuscoMap/ruscomap/commit/1f17f33ca32fdc224d02022b58fa5f3ccabba073)]
|
|
||||||
- [ ] Creare logo RuscoMap
|
|
||||||
- [ ] Scatta la foto del marker da uploadare direttamente in app (su alcuni smartphone gia lo fa)
|
|
||||||
- [ ] Possibilità di aggiungere piu di una foto per un marker
|
|
||||||
- [ ] Implemtare review per moderazione rusco inserito. switch per on/off moderazione da annello
|
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
---
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ISTRUZIONI INSTALLAZIONE
|
|
||||||
|
|
||||||
## Installazione dipendenze
|
|
||||||
|
|
||||||
#### Installa mariadb, jq e npm
|
|
||||||
<code>sudo apt update && sudo apt install mariadb jq npm</code>
|
|
||||||
|
|
||||||
#### Clona il git
|
|
||||||
```
|
|
||||||
# crea la cartella
|
|
||||||
mkdir /var/www/html/leaflet/; cd /var/www/html/leaflet/;
|
|
||||||
|
|
||||||
# clona il repo
|
|
||||||
git clone https://git.lattuga.net/RuscoMap/ruscomap.git; cd ruscomap
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Installa node e nvm
|
|
||||||
Curl da sito ufficiale [qui](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script) <br>
|
|
||||||
_trobleshooting: cerca nvm in .bashrc_
|
|
||||||
|
|
||||||
```
|
|
||||||
# installalo
|
|
||||||
nvm install
|
|
||||||
|
|
||||||
# usa la versione node spcificata nel file .nvmrc
|
|
||||||
cd /var/www/html/leaflet/ruscomap/; nvm use
|
|
||||||
|
|
||||||
# sempre da cartella git
|
|
||||||
cd /var/www/html/leaflet/ruscomap/;
|
|
||||||
|
|
||||||
# inzializza Db
|
|
||||||
mysql < initDb.sql
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
##### dipendenze
|
|
||||||
<code>npm i express leaflet leaflet.locatecontrol multer mysql config</code>
|
|
||||||
|
|
||||||
## Configura ruscomap
|
|
||||||
|
|
||||||
#### Personalizza il file di configurazione db
|
|
||||||
<code>nano /var/www/html/leaflet/ruscomap/server/config/default.json</code>
|
|
||||||
|
|
||||||
#### Apri porta sul firewall
|
|
||||||
<code>sudo iptables -A INPUT -p tcp --dport 3000 -j ACCEPT</code>
|
|
||||||
|
|
||||||
#### Cre l'utente
|
|
||||||
sudo adduser ruscone
|
|
||||||
|
|
||||||
|
|
||||||
#### Crea il servzio
|
|
||||||
<code>nano /etc/systemd/system/ruscomap.service</code>
|
|
||||||
|
|
||||||
```
|
|
||||||
[Unit]
|
|
||||||
Description=Ruscomap Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Unit]
|
|
||||||
Description=Ruscomap Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=
|
|
||||||
WorkingDirectory=/var/www/html/leaflet/ruscomap/server
|
|
||||||
ExecStart=/bin/bash -c "node index.js"
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
<code>systemctl daemon-reload</code>
|
|
||||||
|
|
||||||
|
|
||||||
##### Dai i permessi a www-data per ruscomap
|
|
||||||
```
|
|
||||||
cd /var/www/html/leaflet/ruscomap
|
|
||||||
chown -R www-data:www-data public
|
|
||||||
```
|
|
||||||
|
|
||||||
##### avvialo e abilitalo a startarsi in automatico
|
|
||||||
```
|
|
||||||
sudo systemctl start ruscomap.service
|
|
||||||
sudo systemctl enable ruscomap.service
|
|
||||||
sudo systemctl status ruscomap.service
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Crea il file conf di apache
|
|
||||||
|
|
||||||
<code>nano /etc/apache2/sites-enabled/ruscomap.conf</code>
|
|
||||||
|
|
||||||
```
|
|
||||||
#PORT 80
|
|
||||||
<VirtualHost ruscomap.myserver:80>
|
|
||||||
|
|
||||||
ServerName ruscomap.myserver
|
|
||||||
DocumentRoot /var/www/html/leaflet/ruscomap/public
|
|
||||||
|
|
||||||
ProxyPass / http://127.0.0.1:3000/
|
|
||||||
ProxyPassReverse / http://127.0.0.0.1:3000/
|
|
||||||
|
|
||||||
RewriteEngine on
|
|
||||||
#RewriteCond %{HTTP:Upgrade} =websocket
|
|
||||||
#RewriteRule /(.*) ws://localhost:3000/$1 [P,L]
|
|
||||||
|
|
||||||
RewriteCond %{SERVER_NAME} =ruscomap.myserver
|
|
||||||
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
#PORT 80
|
|
||||||
<VirtualHost ruscomap.myserver:80>
|
|
||||||
|
|
||||||
DocumentRoot /var/www/html/leaflet/ruscomap/public
|
|
||||||
ServerName ruscomap.myserver
|
|
||||||
|
|
||||||
ProxyPass / http://localhost:3000/
|
|
||||||
ProxyPassReverse / http://localhost:3000/
|
|
||||||
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteCond %{HTTP:Upgrade} =websocket
|
|
||||||
RewriteRule /(.*) ws://localhost:3000/$1 [P,L]
|
|
||||||
|
|
||||||
RewriteCond %{SERVER_NAME} =ruscomap.myserver
|
|
||||||
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
|
|
||||||
</VirtualHost>
|
|
||||||
|
|
||||||
#443
|
|
||||||
DocumentRoot /var/www/html/leaflet/ruscomap/public
|
|
||||||
ServerName ruscomap.myserver
|
|
||||||
|
|
||||||
#Protocols h2 http/2
|
|
||||||
|
|
||||||
ProxyPass / http://localhost:3000/
|
|
||||||
ProxyPassReverse / http://localhost:3000/
|
|
||||||
|
|
||||||
RewriteEngine on
|
|
||||||
#RewriteCond %{HTTP:Upgrade} =websocket
|
|
||||||
#RewriteRule /(.*) ws://localhost:3000/$1 [P,L]
|
|
||||||
|
|
||||||
LogFormat "%t %h \"%r\" %>s \"%{User-Agent}i\"" custom
|
|
||||||
|
|
||||||
ErrorLog ${APACHE_LOG_DIR}/ruscomap.log
|
|
||||||
CustomLog ${APACHE_LOG_DIR}/ruscomap-access.log custom
|
|
||||||
|
|
||||||
SSLEngine on
|
|
||||||
SSLCertificateFile /etc/letsencrypt/live/ruscomap.myserver/fullchain.pem
|
|
||||||
SSLCertificateKeyFile /etc/letsencrypt/live/ruscomap.amyserver/privkey.pem
|
|
||||||
|
|
||||||
# HSTS una settimana 604800, per settare un anno: max-age=31536000
|
|
||||||
#Header always set Strict-Transport-Security "max-age=1,; includeSubDomain>
|
|
||||||
|
|
||||||
</VirtualHost>
|
|
||||||
|
|
||||||
```
|
|
||||||
##### restarta apache
|
|
||||||
```
|
|
||||||
sudo systemctl restart apache2.service
|
|
||||||
sudo systemctl status apache2.service
|
|
||||||
|
|
||||||
```
|
|
||||||
##### Debug
|
|
||||||
```
|
|
||||||
#### If
|
|
||||||
Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration
|
|
||||||
#### Then
|
|
||||||
sudo a2enmod proxy_http
|
|
||||||
```
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
## Analisi tecnica
|
||||||
|
|
||||||
|
### Desiderata:
|
||||||
|
- Mappa visualizzazione marker custom
|
||||||
|
- Inserimento e ricerca
|
||||||
|
- Eliminazione automatica con cron (h24) o timer e da parte dell'utente, con modifica
|
||||||
|
|
||||||
|
### Tipologia di utenti:
|
||||||
|
- Anonimo con captcha, da chiarire eventuali costi
|
||||||
|
- Account per inserimento, modifica ed eliminazione?
|
||||||
|
- Login classico con email, nick pubb, passwd
|
||||||
|
- Signup
|
||||||
|
- Admin
|
||||||
|
|
||||||
|
### Marker custom geojson:
|
||||||
|
#### Composizione:
|
||||||
|
- Id
|
||||||
|
- Coords
|
||||||
|
- Form
|
||||||
|
- Titolo
|
||||||
|
- Foto
|
||||||
|
- Descrizione
|
||||||
|
- Qualità:
|
||||||
|
- Non so
|
||||||
|
- Ottimo
|
||||||
|
- Buono
|
||||||
|
- Decente
|
||||||
|
- Scarso
|
||||||
|
|
||||||
|
#### Semi automatico
|
||||||
|
- Status:
|
||||||
|
- Inserimento
|
||||||
|
- In attesa
|
||||||
|
- E' stata presa
|
||||||
|
|
||||||
|
### Aggiunta Anonimo o con account? :
|
||||||
|
- Posizionamento marker
|
||||||
|
- Compilazione form
|
||||||
|
|
||||||
|
### Eliminazione:
|
||||||
|
- Admin
|
||||||
|
- Cron h24 o timer
|
||||||
|
- Creatore
|
||||||
|
|
||||||
|
### Modifica:
|
||||||
|
- Proprietario
|
||||||
|
- Admin
|
||||||
|
- Utenti solo stato
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
## BackEnd
|
||||||
|
#### 1) API
|
||||||
|
#### 2) Login/Signup
|
||||||
|
#### 3) Marker
|
||||||
|
- Inserimento - Auth
|
||||||
|
- Modifica - Auth
|
||||||
|
- Cancellazione - Auth
|
||||||
|
- Lista - No auth
|
||||||
|
|
||||||
# ISTRUZIONI ADMIN
|
#### 4) Controller
|
||||||
|
- Inserimento che modifica - Normalizzazione del marker inserito dall'utente a shapefile
|
||||||
|
- Cancellazione da Proprietario, Admin e cron
|
||||||
|
- Lista
|
||||||
|
<br>
|
||||||
|
|
||||||
#### Script per cancellare tutti i record della table "markers" più vecchi di 24h (automatico)
|
|
||||||
|
|
||||||
Si trova in [<code>/var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh</code>](script/pulisci_vecchio_rusco.sh)
|
## FrontEnd
|
||||||
|
#### 1) Ricerca per titolo e descrizione, con lista filtrati dei marker e visualizzazione su mappa
|
||||||
##### Imposta lo script su cron per essere eseguito ogni 24h
|
#### 2) Mappa con lista di marker filtrata o meno
|
||||||
|
#### 3) Inserimento:
|
||||||
```
|
- Modalita' che nasconde la barra di ricerca
|
||||||
# Per eseguire tutti i giorni a mezzanotte lo script che elimina tutti i marker più vecchi di 24h:
|
- All'inserimento di un marker mostra il form
|
||||||
|
- Modalita' d'inserimento
|
||||||
# Entra in modalità edit su cron:
|
- Mobile: Mirino sulla mappa, premere btn + per conferma e.g. osmand
|
||||||
crontab -e
|
- PC: click sulla mappa
|
||||||
|
- Form con campi dello shapefile con pulsante di conferma
|
||||||
# Edita il file aggiungendo la riga:
|
#### 4) Login
|
||||||
0 0 * * * /var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh
|
<br>
|
||||||
|
|
||||||
# Assicurati che lo script abbia i permessi di esecuzione:
|
|
||||||
ls -l /var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh
|
|
||||||
|
|
||||||
# Se mancano, impostali:
|
|
||||||
chmod +x /var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Script per cancellare tutti i record della table "markers" più vecchi di 24h (manuale)
|
|
||||||
|
|
||||||
Si trova in [<code>/var/www/html/leaflet/ruscomap/script/pulisci_manualmente_vecchio_rusco.sh</code>](script/pulisci_manualmente_vecchio_rusco.sh)
|
|
||||||
|
|
||||||
#### Script per aggiornare ruscomap
|
|
||||||
|
|
||||||
Si trova in [<code>/var/www/html/leaflet/ruscomap/script/AggiornaRuscoMap.sh</code>](script/AggiornaRuscoMap.sh)
|
|
||||||
|
|
||||||
#### Script per cancellare tutti i record della table "markers"
|
|
||||||
|
|
||||||
Si trova in [<code>/var/www/html/leaflet/ruscomap/script/delete_rusco.sh</code>](script/delete_rusco.sh)
|
|
||||||
|
|
||||||
#### Cancella un singolo record del db
|
|
||||||
|
|
||||||
```
|
|
||||||
mariadb -u <utente_del_config/default.json> -p
|
|
||||||
|
|
||||||
show databases;
|
|
||||||
use ruscomap;
|
|
||||||
show tables;
|
|
||||||
select * from markers;
|
|
||||||
DELETE FROM markers WHERE filename = '0a9f02167f85c845db2d4b81bbeef9d5';
|
|
||||||
```
|
|
14
compose.yml
|
@ -1,14 +0,0 @@
|
||||||
services:
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: mariadb
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
MARIADB_DATABASE: ruscomap
|
|
||||||
MYSQL_USER: ruscone
|
|
||||||
MYSQL_PASSWORD: password
|
|
||||||
MYSQL_RANDOM_ROOT_PASSWORD: '1'
|
|
||||||
ports:
|
|
||||||
- 3306:3306
|
|
||||||
volumes:
|
|
||||||
- ./db_data:/var/lib/mysql
|
|
12
initDb.sql
|
@ -1,12 +0,0 @@
|
||||||
CREATE DATABASE ruscomap;
|
|
||||||
CREATE USER 'ruscone'@'localhost' IDENTIFIED BY 'password';
|
|
||||||
GRANT ALL PRIVILEGES ON ruscomap.* TO 'ruscone'@'localhost';
|
|
||||||
FLUSH PRIVILEGES;
|
|
||||||
|
|
||||||
CREATE TABLE ruscomap.markers (
|
|
||||||
name VARCHAR(256) NOT NULL,
|
|
||||||
description VARCHAR(1024),
|
|
||||||
filename VARCHAR(256) NOT NULL,
|
|
||||||
coordinate POINT NOT NULL,
|
|
||||||
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
||||||
);
|
|
|
@ -1,209 +0,0 @@
|
||||||
/*BODY*/
|
|
||||||
body {
|
|
||||||
margin: 0px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*CONTAINER*/
|
|
||||||
#container {
|
|
||||||
display: flexbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*MAP*/
|
|
||||||
#map {
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*BOTTONE ALTO DX*/
|
|
||||||
|
|
||||||
#addMarkerBtn {
|
|
||||||
z-index: 1000;
|
|
||||||
background: rgb(255, 255, 255);
|
|
||||||
width: 40px;
|
|
||||||
height: 38px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-image {
|
|
||||||
width: 5px;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*FORM INSERIMENTO MARKER*/
|
|
||||||
|
|
||||||
/*CONTENITORE DEL FORM*/
|
|
||||||
#markerFormContainer {
|
|
||||||
display: none;
|
|
||||||
z-index: 999;
|
|
||||||
position: absolute;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
left:42px;
|
|
||||||
right: 42px;
|
|
||||||
text-align: center;
|
|
||||||
width: fit-content;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*FORM*/
|
|
||||||
#markerForm {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 10px;
|
|
||||||
margin: 23px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*OGEETTI DEL FORM*/
|
|
||||||
#remainingForm {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*BOH*/
|
|
||||||
#markerForm > button {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*AREA NOME MARKER*/
|
|
||||||
input[type='file'] {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*AREA DESCRIZIONE MARKER*/
|
|
||||||
textarea[name="description"] {
|
|
||||||
width: 200px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
.image {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: left;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*BOTTONE SCEGLI IMMAGINE*/
|
|
||||||
.file-input {
|
|
||||||
display: none; /* Hide the file input */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*BOTTONE SCEGLI IMMAGINE*/
|
|
||||||
.file-label {
|
|
||||||
background-color: #e9e9ed; /* Button color */
|
|
||||||
color: rgb(0, 0, 0);
|
|
||||||
border: 100cm;
|
|
||||||
border-color: black;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-radius: 50px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 10px; /* Space between button and file name */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*EFFETTO BOTTONE SCEGLI IMMAGINE*/
|
|
||||||
.file-label:hover {
|
|
||||||
background-color: #bec3c9; /* Background color on hover */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*NOME FILE SCELTO*/
|
|
||||||
.file-chosen {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*POPUP MARKER*/
|
|
||||||
|
|
||||||
.leaflet-popup-content-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content>img {
|
|
||||||
max-width: 230px;
|
|
||||||
max-height: 230px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content p {
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
white-space: normal;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content h1 {
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
white-space: normal;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content-wrapper {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*POPUP INZIALE*/
|
|
||||||
|
|
||||||
.popup {
|
|
||||||
display: flex; /* Hidden by default */
|
|
||||||
position: fixed;
|
|
||||||
top: 75%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
padding: 20px;
|
|
||||||
z-index: 1000;
|
|
||||||
text-align: cemter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .popup img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
} */
|
|
||||||
|
|
||||||
#popupstart {
|
|
||||||
height: 22px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#istruzioni {
|
|
||||||
font-size: 14.2px;
|
|
||||||
width: 200px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#gps-button {
|
|
||||||
z-index: 1000;
|
|
||||||
background: rgb(255, 255, 255);
|
|
||||||
width: 40px;
|
|
||||||
height: 38px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
margin-top: 60px;
|
|
||||||
margin-right: 10px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tutorial {
|
|
||||||
font-size: 18px;
|
|
||||||
width: 40wh;
|
|
||||||
|
|
||||||
}
|
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 4.5 KiB |
|
@ -1,158 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="./js/dist/leaflet.css"
|
|
||||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
|
||||||
crossorigin=""
|
|
||||||
/>
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="../img/trashw.png" />
|
|
||||||
<script
|
|
||||||
src="./js/dist/leaflet.js"
|
|
||||||
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
|
||||||
crossorigin=""
|
|
||||||
></script>
|
|
||||||
<link rel="stylesheet" href="/css/map.css" />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
html,
|
|
||||||
body,
|
|
||||||
#map {
|
|
||||||
height: 100%;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
#version {
|
|
||||||
position: absolute;
|
|
||||||
font-family: monospace;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 10px;
|
|
||||||
z-index: 9999;
|
|
||||||
background: white;
|
|
||||||
border-top-right-radius: 15px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- importa control.locate senza cdn -->
|
|
||||||
<link rel="stylesheet" href="./js/dist/L.Control.Locate.css" />
|
|
||||||
<title>RuscoMap</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<button id="addMarkerBtn">
|
|
||||||
<img src="../img/marker-icon18.png" alt="Add Marker" />
|
|
||||||
</button>
|
|
||||||
<div id="markerFormContainer">
|
|
||||||
<form id="markerForm" enctype="multipart/form-data">
|
|
||||||
<div id="noticeCoordsPicker" style="display: none">
|
|
||||||
<text
|
|
||||||
>Clicca sul punto della mappa in cui vuoi inserire il rusco
|
|
||||||
avvistato</text
|
|
||||||
>
|
|
||||||
<input id="formInputCoordY" name="lat" type="hidden" />
|
|
||||||
<input id="formInputCoordX" name="long" type="hidden" />
|
|
||||||
</div>
|
|
||||||
<div id="remainingForm" style="display: none">
|
|
||||||
<label>Nome</label>
|
|
||||||
<br />
|
|
||||||
<input name="name" required type="text" />
|
|
||||||
<br /><br />
|
|
||||||
<label>Descrizione</label>
|
|
||||||
<br />
|
|
||||||
<textarea name="description" required></textarea>
|
|
||||||
<br /><br />
|
|
||||||
<div class="file-upload">
|
|
||||||
<input
|
|
||||||
name="image"
|
|
||||||
required
|
|
||||||
type="file"
|
|
||||||
id="file-input"
|
|
||||||
class="file-input"
|
|
||||||
accept="image/x-png,image/jpeg,image/jpg"
|
|
||||||
/>
|
|
||||||
<label for="file-input" class="file-label">Scegli File</label>
|
|
||||||
<br /><br />
|
|
||||||
<span class="file-chosen"> </span>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<button>Aggiungi Marker</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div id="map"></div>
|
|
||||||
|
|
||||||
<!-- bottone gps -->
|
|
||||||
<!-- <button id="gps-button" type="button">
|
|
||||||
<img src="../img/target30.png" alt="GPS" style="display: flex"> </button> -->
|
|
||||||
<div class="popup" id="popup">
|
|
||||||
<!-- <img src="qualcosa.jpg" alt="Popup Image"> -->
|
|
||||||
<p id="istruzioni">
|
|
||||||
<img src="../img/trashg.png" alt="rusco" width="20" height="20" /><b
|
|
||||||
>RuscoMap</b
|
|
||||||
>
|
|
||||||
è una mappa dove utenti in anonimo possono inserire dei marker con nome,
|
|
||||||
descrizione e foto di oggetti abbandonati, segnalandoli a tutti i
|
|
||||||
visitatori della mappa. <br />
|
|
||||||
<br />
|
|
||||||
Sulla falsa riga del <i>te lo regalo se vieni a prenderlo</i>, questo è
|
|
||||||
più il
|
|
||||||
<i>segnalo che c'è 'sta roba lì, è tua se te la vai a prendere</i>.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Clicca <a href="./tutorial.html">qui</a> per leggere il tutorial.
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<button id="popupstart" type="button" onclick="closePopup()">X</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="version"></div>
|
|
||||||
<script>
|
|
||||||
function closePopup() {
|
|
||||||
const popup = document.getElementById("popup");
|
|
||||||
popup.style.display = "none";
|
|
||||||
}
|
|
||||||
// Popup si chiude automaticamente dopo 13 secondi
|
|
||||||
setTimeout(closePopup, 13000);
|
|
||||||
|
|
||||||
window.addEventListener("load", async () => {
|
|
||||||
const response = await fetch(`/version`);
|
|
||||||
const { version } = await response.json();
|
|
||||||
const domVersion = document.querySelector("#version");
|
|
||||||
|
|
||||||
domVersion.innerHTML = `v${version}`;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Add a click event listener to the button
|
|
||||||
const gpsButton = document.getElementById("gps-button");
|
|
||||||
gpsButton.addEventListener("click", function () {
|
|
||||||
if (lc.isFollowing()) {
|
|
||||||
lc.stop();
|
|
||||||
} else {
|
|
||||||
lc.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script defer src="./js/dayjs/dayjs.min.js"></script>
|
|
||||||
<script defer src="./js/dist/L.Control.Locate.min.js"></script>
|
|
||||||
<script
|
|
||||||
defer
|
|
||||||
type="module"
|
|
||||||
type="text/javascript"
|
|
||||||
src="/js/map.js"
|
|
||||||
></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
1
public/js/dayjs/dayjs.min.js
vendored
63
public/js/dist/L.Control.Locate.css
vendored
|
@ -1,63 +0,0 @@
|
||||||
.leaflet-control-locate a {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.leaflet-control-locate a .leaflet-control-locate-location-arrow {
|
|
||||||
display: inline-block;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin: 7px;
|
|
||||||
background-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="black" d="M445 4 29 195c-48 23-32 93 19 93h176v176c0 51 70 67 93 19L508 67c16-38-25-79-63-63z"/></svg>');
|
|
||||||
}
|
|
||||||
.leaflet-control-locate a .leaflet-control-locate-spinner {
|
|
||||||
display: inline-block;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin: 7px;
|
|
||||||
background-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="black" d="M304 48a48 48 0 1 1-96 0 48 48 0 0 1 96 0zm-48 368a48 48 0 1 0 0 96 48 48 0 0 0 0-96zm208-208a48 48 0 1 0 0 96 48 48 0 0 0 0-96zM96 256a48 48 0 1 0-96 0 48 48 0 0 0 96 0zm13 99a48 48 0 1 0 0 96 48 48 0 0 0 0-96zm294 0a48 48 0 1 0 0 96 48 48 0 0 0 0-96zM109 61a48 48 0 1 0 0 96 48 48 0 0 0 0-96z"/></svg>');
|
|
||||||
animation: leaflet-control-locate-spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
.leaflet-control-locate.active a .leaflet-control-locate-location-arrow {
|
|
||||||
background-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="rgb(32, 116, 182)" d="M445 4 29 195c-48 23-32 93 19 93h176v176c0 51 70 67 93 19L508 67c16-38-25-79-63-63z"/></svg>');
|
|
||||||
}
|
|
||||||
.leaflet-control-locate.following a .leaflet-control-locate-location-arrow {
|
|
||||||
background-image: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="rgb(252, 132, 40)" d="M445 4 29 195c-48 23-32 93 19 93h176v176c0 51 70 67 93 19L508 67c16-38-25-79-63-63z"/></svg>');
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-touch .leaflet-bar .leaflet-locate-text-active {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 200px;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
.leaflet-touch .leaflet-bar .leaflet-locate-text-active .leaflet-locate-icon {
|
|
||||||
padding: 0 5px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-control-locate-location circle {
|
|
||||||
animation: leaflet-control-locate-throb 4s ease infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes leaflet-control-locate-throb {
|
|
||||||
0% {
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
stroke-width: 3;
|
|
||||||
transform: scale(0.8, 0.8);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes leaflet-control-locate-spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*# sourceMappingURL=L.Control.Locate.css.map */
|
|
4
public/js/dist/L.Control.Locate.min.js
vendored
14419
public/js/dist/leaflet-src.esm.js
vendored
1
public/js/dist/leaflet-src.esm.js.map
vendored
14512
public/js/dist/leaflet-src.js
vendored
1
public/js/dist/leaflet-src.js.map
vendored
|
@ -1,118 +0,0 @@
|
||||||
import { basicElements } from "./getHtmlElements.js";
|
|
||||||
import { createMarkerTemp } from "./markerHandler.js";
|
|
||||||
import { mapInit } from "./mapInit.js";
|
|
||||||
|
|
||||||
export function initEvents(map) {
|
|
||||||
let editMode = false;
|
|
||||||
let isTmpMarkerSet = false;
|
|
||||||
let tmpMarkerSet = {};
|
|
||||||
|
|
||||||
const [
|
|
||||||
addMarkerBtn,
|
|
||||||
markerFormContainer,
|
|
||||||
markerForm,
|
|
||||||
noticeCoordsPicker,
|
|
||||||
remainingForm,
|
|
||||||
] = basicElements();
|
|
||||||
|
|
||||||
markerForm.addEventListener("submit", processForm);
|
|
||||||
|
|
||||||
function setStyleForEditing() {
|
|
||||||
markerFormContainer.style.display = "flex";
|
|
||||||
noticeCoordsPicker.style.display = "block"; //messaggio inserimento
|
|
||||||
remainingForm.style.display = "none"; // form dati
|
|
||||||
// imposta una X rossa come icona pulsante, come icona cursore un marker e entra nella modalità inserimento.
|
|
||||||
document.getElementById("addMarkerBtn").innerHTML =
|
|
||||||
'<img src="../img/xred20.png" alt="Button Image" />';
|
|
||||||
document.getElementById("map").style =
|
|
||||||
'cursor: url("js/dist/images/marker-icon.png") 13 41, auto;';
|
|
||||||
}
|
|
||||||
|
|
||||||
function setStyleNotEditing() {
|
|
||||||
markerForm.reset();
|
|
||||||
document.getElementById("addMarkerBtn").innerHTML =
|
|
||||||
'<img src="../img/marker-icon18.png" alt="Button Image" />';
|
|
||||||
document.getElementById("map").style = "cursor: auto;";
|
|
||||||
noticeCoordsPicker.style.display = "none"; //messaggio inserimento
|
|
||||||
remainingForm.style.display = "none"; // form dati
|
|
||||||
markerFormContainer.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
addMarkerBtn.onclick = function (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
if (!editMode) {
|
|
||||||
setStyleForEditing();
|
|
||||||
editMode = true;
|
|
||||||
isTmpMarkerSet = false;
|
|
||||||
tmpMarkerSet = {};
|
|
||||||
document.querySelector(".file-chosen").textContent = "";
|
|
||||||
} else {
|
|
||||||
setStyleNotEditing();
|
|
||||||
editMode = false;
|
|
||||||
map.removeLayer(tmpMarkerSet);
|
|
||||||
isTmpMarkerSet = false;
|
|
||||||
tmpMarkerSet = {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//event listener onclick on map, inserisce marker il temporaneo e mostra il remainingForm
|
|
||||||
map.on("click", function (e) {
|
|
||||||
if (editMode && !isTmpMarkerSet) {
|
|
||||||
let formInputCoordY = document.getElementById("formInputCoordY");
|
|
||||||
let formInputCoordX = document.getElementById("formInputCoordX");
|
|
||||||
formInputCoordY.value = e.latlng.lat;
|
|
||||||
formInputCoordX.value = e.latlng.lng;
|
|
||||||
noticeCoordsPicker.style.display = "none";
|
|
||||||
remainingForm.style.display = "block";
|
|
||||||
map.getContainer().style.cursor = "auto";
|
|
||||||
const formattedDate = new Date().toISOString();
|
|
||||||
const tmpMarker = {
|
|
||||||
coordinate: { x: formInputCoordX.value, y: formInputCoordY.value },
|
|
||||||
name: "",
|
|
||||||
description:
|
|
||||||
"Compila il form per aggiungere un marker qui. Oppure annulla l'inserimento del marker cliccando sulla X in alto a destra",
|
|
||||||
filename: "../img/trashw.png",
|
|
||||||
ts: formattedDate,
|
|
||||||
};
|
|
||||||
tmpMarkerSet = createMarkerTemp(tmpMarker, L, map, true);
|
|
||||||
isTmpMarkerSet = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleSentFormStyle() {
|
|
||||||
document.getElementById("addMarkerBtn").innerHTML =
|
|
||||||
'<img src="../img/marker-icon18.png" alt="Button Image" />';
|
|
||||||
document.getElementById("map").style = "cursor: auto;";
|
|
||||||
markerFormContainer.style.display = "none"; //tutto
|
|
||||||
const remainingForm = document.getElementById("remainingForm");
|
|
||||||
remainingForm.style.display = "none";
|
|
||||||
document.getElementById("addMarkerBtn").innerHTML =
|
|
||||||
'<img src="../img/marker-icon18.png" alt="Button Image" />';
|
|
||||||
document.getElementById("markerFormContainer").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
async function processForm(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
handleSentFormStyle();
|
|
||||||
// imposta un marker come icona pulsante, icona cursore normale e esce dalla modalità inserimento.
|
|
||||||
editMode = false;
|
|
||||||
isTmpMarkerSet = false;
|
|
||||||
const markerForm = document.getElementById("markerForm");
|
|
||||||
const formData = new FormData(markerForm);
|
|
||||||
markerForm.reset();
|
|
||||||
|
|
||||||
await fetch("/uploadMarker", {
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
}).then(async () => {
|
|
||||||
await map.fetchNewMarkers().then(() => map.removeLayer(tmpMarkerSet));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("file-input").addEventListener("change", function () {
|
|
||||||
const fileName = this.files[0] ? this.files[0].name : "No file chosen";
|
|
||||||
const truncatedFileName =
|
|
||||||
fileName.length > 21 ? fileName.slice(0, 21) + "..." : fileName;
|
|
||||||
document.querySelector(".file-chosen").textContent = truncatedFileName;
|
|
||||||
});
|
|
|
@ -1,14 +0,0 @@
|
||||||
export function basicElements() {
|
|
||||||
const addMarkerBtn = document.getElementById("addMarkerBtn");
|
|
||||||
const markerFormContainer = document.getElementById("markerFormContainer");
|
|
||||||
const markerForm = document.getElementById("markerForm");
|
|
||||||
const noticeCoordsPicker = document.getElementById("noticeCoordsPicker");
|
|
||||||
const remainingForm = document.getElementById("remainingForm");
|
|
||||||
return [
|
|
||||||
addMarkerBtn,
|
|
||||||
markerFormContainer,
|
|
||||||
markerForm,
|
|
||||||
noticeCoordsPicker,
|
|
||||||
remainingForm,
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
import { initMarkers, createMarker } from "./markerHandler.js";
|
|
||||||
import { initEvents } from "./eventHandler.js";
|
|
||||||
import { mapInit } from "./mapInit.js";
|
|
||||||
|
|
||||||
let editMode = false;
|
|
||||||
let lastUpdateCheck = Date.now();
|
|
||||||
|
|
||||||
const map = mapInit();
|
|
||||||
|
|
||||||
initEvents(map);
|
|
||||||
|
|
||||||
async function fetchAllMarkers() {
|
|
||||||
const response = await fetch("/fetchMarkers");
|
|
||||||
|
|
||||||
let markers = await response.json();
|
|
||||||
console.log(markers);
|
|
||||||
markers.forEach((marker) => {
|
|
||||||
createMarker(marker, L, map);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchNewMarkers() {
|
|
||||||
const searchParams = new URLSearchParams({ fromDate: lastUpdateCheck });
|
|
||||||
|
|
||||||
const response = await fetch(`/updateMarkers?${searchParams.toString()}`);
|
|
||||||
|
|
||||||
const markers = await response.json();
|
|
||||||
|
|
||||||
markers.forEach((marker) => {
|
|
||||||
createMarker(marker, L, map);
|
|
||||||
});
|
|
||||||
|
|
||||||
lastUpdateCheck = Date.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
const main = async () => {
|
|
||||||
await fetchAllMarkers();
|
|
||||||
|
|
||||||
setInterval(fetchNewMarkers, 5000);
|
|
||||||
};
|
|
||||||
|
|
||||||
main()
|
|
||||||
.then(() => {
|
|
||||||
console.log("Completed");
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
|
@ -1,60 +0,0 @@
|
||||||
import { initMarkers, createMarker } from "./markerHandler.js";
|
|
||||||
import { initEvents } from "./eventHandler.js";
|
|
||||||
import { mapInit } from "./mapInit.js";
|
|
||||||
|
|
||||||
|
|
||||||
let editMode = false;
|
|
||||||
let map = mapInit();
|
|
||||||
let lastUpdateCheck = new Date().getTime();
|
|
||||||
let markersArray = []; // Array to hold the markers
|
|
||||||
|
|
||||||
// Initialize events
|
|
||||||
initEvents(map);
|
|
||||||
fetchAllMarkers();
|
|
||||||
|
|
||||||
// Function to fetch all markers initially
|
|
||||||
async function fetchAllMarkers() {
|
|
||||||
const response = await fetch('/markers');
|
|
||||||
const markers = await response.json();
|
|
||||||
|
|
||||||
// Clear existing markers before adding new ones
|
|
||||||
clearMarkers();
|
|
||||||
|
|
||||||
markers.forEach(marker => {
|
|
||||||
createMarker(marker, L, map);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to clear existing markers from the map
|
|
||||||
function clearMarkers() {
|
|
||||||
markersArray.forEach(marker => {
|
|
||||||
map.removeLayer(marker); // Remove each marker from the map
|
|
||||||
});
|
|
||||||
markersArray = []; // Clear the array
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to fetch new markers periodically
|
|
||||||
export async function fetchNewMarkers() {
|
|
||||||
let response = await fetch('/updateMarkers?' + new URLSearchParams({ fromDate: lastUpdateCheck }), {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
|
|
||||||
let markers = await response.json();
|
|
||||||
console.log(markers);
|
|
||||||
|
|
||||||
// Clear existing markers before adding new ones
|
|
||||||
clearMarkers();
|
|
||||||
|
|
||||||
markers.forEach(marker => {
|
|
||||||
const newMarker = createMarker(marker, L, map);
|
|
||||||
markersArray.push(newMarker); // Store the new marker in the array
|
|
||||||
});
|
|
||||||
|
|
||||||
lastUpdateCheck = new Date().getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set an interval to fetch new markers every 5 seconds
|
|
||||||
setInterval(fetchNewMarkers, 5000);
|
|
||||||
|
|
||||||
// Initial fetch of all markers
|
|
||||||
fetchAllMarkers();
|
|
|
@ -1,18 +0,0 @@
|
||||||
// import L from './../node_modules/leaflet'; // Import Leaflet
|
|
||||||
// import '../../node_modeules/leaflet.locatecontrol'; // Import the Locate Control plugin
|
|
||||||
// import '../../node_modeules/leaflet.locatecontrol/dist/L.Control.Locate.min.css'; // Import styles
|
|
||||||
|
|
||||||
export function mapInit() {
|
|
||||||
const coordsPiazzaMaggiore = [44.49385, 11.34316];
|
|
||||||
const map = L.map("map").setView(coordsPiazzaMaggiore, 13);
|
|
||||||
|
|
||||||
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
|
||||||
maxZoom: 19,
|
|
||||||
attribution:
|
|
||||||
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
L.control.locate().addTo(map);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
const formatDate = (date) => {
|
|
||||||
const day = date.getDate();
|
|
||||||
const month = date.getMonth() + 1;
|
|
||||||
const year = date.getFullYear();
|
|
||||||
|
|
||||||
return `${day}/${month}/${year}`;
|
|
||||||
};
|
|
||||||
const formatTime = (date) => {
|
|
||||||
return date.toTimeString().split(" ")[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
export function initMarkers(markerList, L, map) {
|
|
||||||
markerList.forEach((customMarker) => {
|
|
||||||
const marker = L.marker([customMarker.x, customMarker.y]).addTo(map);
|
|
||||||
const popUpContentTitle = "<h1>" + customMarker.title + "</h1>";
|
|
||||||
const popUpContentdescription = "<p>" + customMarker.description + "</p>";
|
|
||||||
const popUpContentImage =
|
|
||||||
"<img src='/img/" + customMarker.imgName + "'</img>";
|
|
||||||
const popUpContentDate =
|
|
||||||
"<br><p>Inserito il: " +
|
|
||||||
markerData.ts.substring(0, 10) +
|
|
||||||
"<br>alle " +
|
|
||||||
markerData.ts.substring(11, 16) +
|
|
||||||
"</p>";
|
|
||||||
const popUpContent =
|
|
||||||
popUpContentTitle +
|
|
||||||
popUpContentdescription +
|
|
||||||
popUpContentImage +
|
|
||||||
popUpContentDate;
|
|
||||||
marker.bindPopup(popUpContent).openPopup();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createMarker(markerData, L, map, returnMarker = false) {
|
|
||||||
const marker = L.marker([
|
|
||||||
markerData.coordinate.y,
|
|
||||||
markerData.coordinate.x,
|
|
||||||
]).addTo(map);
|
|
||||||
const date = new Date(markerData.ts);
|
|
||||||
|
|
||||||
const popUpContentTitle = "<h1>" + markerData.name + "</h1>";
|
|
||||||
const popUpContentdescription = "<p>" + markerData.description + "</p>";
|
|
||||||
const popUpContentImage =
|
|
||||||
"<img src='/imgs/" + markerData.filename + "'</img>";
|
|
||||||
const popUpContentDate = `<br><p>Inserito il: ${formatDate(
|
|
||||||
date
|
|
||||||
)} <br>alle: ${formatTime(date)}</p>`;
|
|
||||||
|
|
||||||
//const popUpContentHour = "<p>" + "alle: " + markerData.ts.substring(11, 16) + "</p>";
|
|
||||||
const popUpContent =
|
|
||||||
popUpContentTitle +
|
|
||||||
popUpContentdescription +
|
|
||||||
popUpContentImage +
|
|
||||||
popUpContentDate; //+ popUpContentHour
|
|
||||||
marker.bindPopup(popUpContent);
|
|
||||||
if (returnMarker) {
|
|
||||||
return marker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createMarkerTemp(markerData, L, map, returnMarker = false) {
|
|
||||||
const marker = L.marker([
|
|
||||||
markerData.coordinate.y,
|
|
||||||
markerData.coordinate.x,
|
|
||||||
]).addTo(map);
|
|
||||||
const popUpContentdescription = "<p>" + markerData.description + "</p>";
|
|
||||||
const popUpContent = popUpContentdescription;
|
|
||||||
marker.bindPopup(popUpContent);
|
|
||||||
if (returnMarker) {
|
|
||||||
return marker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateMarkers(markerList, L, map) {
|
|
||||||
const layers = L.LayerGroup(); //layers contains all markers..
|
|
||||||
const contained = []; //makers in map boundingbox
|
|
||||||
|
|
||||||
layers.eachLayer(function (l) {
|
|
||||||
if (
|
|
||||||
layer instanceof L.Marker &&
|
|
||||||
map.getBounds().contains(layer.getLatLng())
|
|
||||||
)
|
|
||||||
contained.push(layer);
|
|
||||||
});
|
|
||||||
console.log(contained);
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="../img/trashw.png" />
|
|
||||||
<link rel="stylesheet" href="/css/map.css" />
|
|
||||||
<title>RuscoMap Tutorial</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
padding: 14wh;
|
|
||||||
border: 10px solid #ccc;
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
/* width: 300px;
|
|
||||||
height: 200px; */
|
|
||||||
background-color: #fbfbfb;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<center>
|
|
||||||
<h1>
|
|
||||||
<img src="../img/trashg.png" alt="trasher" width="40" height="40" />
|
|
||||||
RuscoMap
|
|
||||||
<img src="../img/trashg.png" alt="trasher" width="40" height="40" />
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p id="tutorial">
|
|
||||||
<b>RuscoMap</b> è una mappa dove utenti in anonimo possono inserire
|
|
||||||
dei marker con nome, descrizione e foto di oggetti abbandonati,
|
|
||||||
segnalandoli a tutti i visitatori della mappa. <br />
|
|
||||||
<br />
|
|
||||||
Si può trovare o inserire la qualunque. L'obiettivo è il riutilizzo,
|
|
||||||
la trasformazione o la riparazione.
|
|
||||||
<br /><br />
|
|
||||||
Sulla falsa riga del <i>"te lo regalo se vieni a prenderlo"</i>,
|
|
||||||
questo è più il
|
|
||||||
<i>"segnalo che c'è 'sta roba lì, è tua se te la vai a prendere"</i>.
|
|
||||||
<br /><br />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<img src="../img/trashg.png" alt="trasher" width="40" height="40" />
|
|
||||||
Tutorial
|
|
||||||
<img src="../img/trashg.png" alt="trasher" width="40" height="40" />
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p id="tutorial">
|
|
||||||
Cliccando sul
|
|
||||||
<img
|
|
||||||
src="../img/marker-icon18.png"
|
|
||||||
alt="marker"
|
|
||||||
width="18"
|
|
||||||
height="30"
|
|
||||||
/>
|
|
||||||
in alto a destra si entra in modalità inserimento. Quindi si posiziona
|
|
||||||
il marker sulla mappa in corrispondenza del rusco avvistato, si
|
|
||||||
compila il form che comparirà in alto e cliccando su "Aggiungi Marker"
|
|
||||||
il nuovo rusco sarà presente sulla mappa. <br /><br />
|
|
||||||
Cliccando su
|
|
||||||
<img
|
|
||||||
src="../img/gps_arrow.png"
|
|
||||||
alt="gpsarrow"
|
|
||||||
width="27"
|
|
||||||
height="18"
|
|
||||||
/>
|
|
||||||
in alto a sinistra verrà invece usato il gps per rilevare le proprie
|
|
||||||
coordinate, in modo da posizionare con più precisione il marker da
|
|
||||||
inserire. Una volta individuata la propria posizione, disattivare il
|
|
||||||
gps ricliccando su
|
|
||||||
<img
|
|
||||||
src="../img/gps_arrow.png"
|
|
||||||
alt="gpsarrow"
|
|
||||||
width="27"
|
|
||||||
height="18"
|
|
||||||
/>
|
|
||||||
e inserire il marker cliccando sul
|
|
||||||
<img
|
|
||||||
src="../img/marker-icon18.png"
|
|
||||||
alt="marker"
|
|
||||||
width="18"
|
|
||||||
height="30"
|
|
||||||
/>
|
|
||||||
in alto a destra.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br /><br />
|
|
||||||
<br /><br />
|
|
||||||
<br /><br />
|
|
||||||
<br /><br />
|
|
||||||
|
|
||||||
<p id="back">
|
|
||||||
Clicca <a href="./index.html">qui</a> per tornare alla mappa.
|
|
||||||
</p>
|
|
||||||
</center>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
17
ruscoapp/.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/server.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
2057
ruscoapp/package-lock.json
generated
Normal file
16
ruscoapp/package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "ruscoapp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"sqlite3": "^5.1.7"
|
||||||
|
}
|
||||||
|
}
|
85
ruscoapp/public/formnewruso.html
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>New GeoJSON Feature Form</title>
|
||||||
|
<!-- Leaflet CSS and JS -->
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
|
||||||
|
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
|
||||||
|
<style>
|
||||||
|
#map {
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>New GeoJSON Feature Form</h2>
|
||||||
|
|
||||||
|
<form id="geojsonForm">
|
||||||
|
<label for="name">Name:</label><br>
|
||||||
|
<input type="text" id="name" name="name"><br><br>
|
||||||
|
|
||||||
|
<label for="description">Description:</label><br>
|
||||||
|
<textarea id="description" name="description"></textarea><br><br>
|
||||||
|
|
||||||
|
<label for="image">Upload Image URL:</label><br>
|
||||||
|
<input type="text" id="image" name="image"><br><br>
|
||||||
|
|
||||||
|
<div id="map"></div><br>
|
||||||
|
|
||||||
|
<button type="submit">Create GeoJSON Feature</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var map = L.map('map').setView([44.49593478876318, 11.343095841047235], 13.5); // Set initial coordinates
|
||||||
|
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 19,
|
||||||
|
}).addTo(map);
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
var marker;
|
||||||
|
|
||||||
|
map.on('click', function (e) {
|
||||||
|
if (marker) {
|
||||||
|
map.removeLayer(marker);
|
||||||
|
}
|
||||||
|
marker = L.marker(e.latlng).addTo(map);
|
||||||
|
document.getElementById('latitude').value = e.latlng.lat;
|
||||||
|
document.getElementById('longitude').value = e.latlng.lng;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('geojsonForm').addEventListener('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var name = document.getElementById('name').value;
|
||||||
|
var description = document.getElementById('description').value;
|
||||||
|
var image = document.getElementById('image').value;
|
||||||
|
var latitude = marker.getLatLng().lat;
|
||||||
|
var longitude = marker.getLatLng().lng;
|
||||||
|
|
||||||
|
var newFeature = {
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"Nome": name,
|
||||||
|
"Descrizione": description,
|
||||||
|
"Foto": image
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [longitude, latitude]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// You can use newFeature to perform further actions, such as sending it to a server or adding it to an existing GeoJSON file.
|
||||||
|
|
||||||
|
console.log(newFeature); // For demonstration purposes, log the new feature to the console
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
BIN
ruscoapp/public/foto/cyclette.jpg
Normal file
After Width: | Height: | Size: 20 KiB |
3
ruscoapp/public/foto/docciafredda.sh
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mat2 --inplace *
|
BIN
ruscoapp/public/foto/tv.jpg
Normal file
After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 618 B |
49
ruscoapp/public/index.css
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#modalAddMarker {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 1002;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modalOverlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modalAddMarker input[type="file"] {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modalAddMarker #nameField,
|
||||||
|
#modalAddMarker #descriptionField,
|
||||||
|
#modalAddMarker #photoField {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#modalSign {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 1002;
|
||||||
|
}
|
||||||
|
|
||||||
|
#registerForm {
|
||||||
|
display: none;
|
||||||
|
}
|
133
ruscoapp/public/index.html
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>RuscoMap</title>
|
||||||
|
<link rel="stylesheet" href="/leaflet.css" />
|
||||||
|
<link rel="stylesheet" href="/index.css" />
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
height: 90dvh;
|
||||||
|
max-height: calc(90dvh - 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
height: 9dvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100dvh;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="modalAddMarker">
|
||||||
|
<form id="addMarkerForm">
|
||||||
|
<div id="latitudeLongitudeField">
|
||||||
|
<label for="latitudeValue">Latitude:</label>
|
||||||
|
<p id="latitudeValue"></p>
|
||||||
|
<label for="longitudeValue">longitude:</label>
|
||||||
|
<p id="longitudeValue"></p>
|
||||||
|
</div>
|
||||||
|
<div id="nameField">
|
||||||
|
<label for="name">Name:</label>
|
||||||
|
<input type="text" id="markerName" name="name" required />
|
||||||
|
</div>
|
||||||
|
<div id="descriptionField">
|
||||||
|
<label for="description">Description:</label>
|
||||||
|
<textarea
|
||||||
|
id="markerDescription"
|
||||||
|
name="description"
|
||||||
|
required
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div id="photoField">
|
||||||
|
<label for="photo">Photo:</label>
|
||||||
|
<input type="file" id="markerPhoto" name="photo" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" id="addMarker">Aggiungi marker</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modalSign">
|
||||||
|
<form id="loginForm">
|
||||||
|
<h2>Login</h2>
|
||||||
|
<div class="container">
|
||||||
|
<label for="username"><b>Username</b></label>
|
||||||
|
<input
|
||||||
|
id="username"
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter Username"
|
||||||
|
name="username"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<label for="password"><b>Password</b></label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Enter Password"
|
||||||
|
name="password"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<button type="submit" name="action" value="loginModal">
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button id="showRegisterForm" formnovalidate>
|
||||||
|
Non hai un account? Registrati
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<form id="registerForm">
|
||||||
|
<h2>Registra</h2>
|
||||||
|
<div class="container">
|
||||||
|
<label for="username"><b>Username</b></label>
|
||||||
|
<input
|
||||||
|
id="username"
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter Username"
|
||||||
|
name="username"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label for="password"><b>Password</b></label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Enter Password"
|
||||||
|
name="password"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button type="submit" name="registerModal" value="register">
|
||||||
|
Registrati
|
||||||
|
</button>
|
||||||
|
<button id="showLoginForm" formnovalidate>
|
||||||
|
Hai un account? Loggati
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modalOverlay"></div>
|
||||||
|
|
||||||
|
<h1>RuscoMap</h1>
|
||||||
|
|
||||||
|
<!-- <button id="showAddMarkerModal">Aggiungi marker</button> -->
|
||||||
|
<button id="showModalSign">Login / Registrazione</button>
|
||||||
|
|
||||||
|
<script src="register.js"></script>
|
||||||
|
<script src="login.js"></script>
|
||||||
|
|
||||||
|
<div id="map"></div>
|
||||||
|
|
||||||
|
<script defer src="/leaflet.js"></script>
|
||||||
|
|
||||||
|
<script defer src="/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
127
ruscoapp/public/index.js
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
let map = null;
|
||||||
|
let points = [];
|
||||||
|
//BOLOGNA
|
||||||
|
const x = 11.343095841047235;
|
||||||
|
const y = 44.49373478876318;
|
||||||
|
const piazzaMaggiore = [x, y];
|
||||||
|
|
||||||
|
var lat = 0;
|
||||||
|
var lng = 0;
|
||||||
|
|
||||||
|
// COORDS ESISTENTI
|
||||||
|
async function downloadRusco() {
|
||||||
|
const resp = await window.fetch("/rusco.geojson");
|
||||||
|
const rusco = await resp.json();
|
||||||
|
return rusco.features;
|
||||||
|
}
|
||||||
|
// SET VIEW
|
||||||
|
async function initMap() {
|
||||||
|
map = L.map("map").setView([44.49593478876318, 11.343095841047235], 13.5);
|
||||||
|
|
||||||
|
// IMPOSTA MAPPA
|
||||||
|
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
|
attribution: "© OpenStreetMap contributors | RuscoMap",
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
loadMarkers();
|
||||||
|
map.on("click", function (e) {
|
||||||
|
lat = e.latlng.lat;
|
||||||
|
lng = e.latlng.lng;
|
||||||
|
document.getElementById("latitudeValue").textContent = lat;
|
||||||
|
document.getElementById("longitudeValue").textContent = lng;
|
||||||
|
// Bind a popup to the marker
|
||||||
|
showModal("modalAddMarker");
|
||||||
|
});
|
||||||
|
setInterval(loadMarkers, 60000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadMarkers() {
|
||||||
|
fetch("http://localhost:3000/getRuschi")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
console.log(data);
|
||||||
|
data.forEach((rusco) => {
|
||||||
|
map.addMarker(rusco);
|
||||||
|
});
|
||||||
|
|
||||||
|
// L.geoJSON(data, {
|
||||||
|
// onEachFeature: function (feature, layer) {
|
||||||
|
// layer.bindPopup('<h2>' +
|
||||||
|
// feature.properties.Nome + '</h2><p>' + feature.properties.Descrizione + '</p><img src="' + feature.properties.Foto + '" alt="Photo" style="width:200px;height:auto;">');
|
||||||
|
// }
|
||||||
|
// }).addTo(map);
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEGUENZA EXEC
|
||||||
|
async function load() {
|
||||||
|
points = await downloadRusco();
|
||||||
|
await initMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showModal(modalName) {
|
||||||
|
const selectedModal = document.getElementById(modalName);
|
||||||
|
const modalOverlay = document.getElementById("modalOverlay");
|
||||||
|
selectedModal.style.display = "block"; // Show the modal
|
||||||
|
modalOverlay.style.display = "block"; // Show the overlay
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectCurrentShownModal() {
|
||||||
|
const modalAddMarker = document.getElementById("modalAddMarker");
|
||||||
|
const modalSign = document.getElementById("modalSign");
|
||||||
|
return modalAddMarker.style.display !== "none" ? modalAddMarker : modalSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
const currentShownModal = detectCurrentShownModal();
|
||||||
|
const modalOverlay = document.getElementById("modalOverlay");
|
||||||
|
currentShownModal.style.display = "none";
|
||||||
|
modalOverlay.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMarker() {
|
||||||
|
const name = document.getElementById("name").value;
|
||||||
|
const description = document.getElementById("description").value;
|
||||||
|
const imageUrl = document.getElementById("photo").value;
|
||||||
|
const latitude = document.getElementById("latitude").value;
|
||||||
|
const longitude = document.getElementById("longitude").value;
|
||||||
|
fetch("http://localhost:3000/addRuschi", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: name,
|
||||||
|
description: description,
|
||||||
|
imageUrl: imageUrl,
|
||||||
|
latitude: latitude,
|
||||||
|
longitude: longitude,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.ok) {
|
||||||
|
// Authentication successful
|
||||||
|
console.log("Added marker");
|
||||||
|
// Redirect the user to the authenticated area or perform other actions
|
||||||
|
} else {
|
||||||
|
// Authentication failed
|
||||||
|
console.error("Error adding marker");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Error adding marker", error);
|
||||||
|
});
|
||||||
|
closeModalAddMarker();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", load);
|
||||||
|
|
||||||
|
const showAddMarkerModal = document.getElementById("showAddMarkerModal");
|
||||||
|
showAddMarkerModal.addEventListener("click", () => showModal("modalAddMarker"));
|
||||||
|
|
||||||
|
const showModalSign = document.getElementById("showModalSign");
|
||||||
|
showModalSign.addEventListener("click", () => showModal("modalSign"));
|
||||||
|
|
||||||
|
const modalOverlay = document.getElementById("modalOverlay");
|
||||||
|
modalOverlay.addEventListener("click", closeModal);
|
39
ruscoapp/public/login.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// login.js
|
||||||
|
document.getElementById('loginForm').addEventListener('submit', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if(event.submitter.id == 'showRegisterForm') {
|
||||||
|
return showRegisterForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
const username = document.getElementById('loginUsername').value;
|
||||||
|
const password = document.getElementById('loginPassword').value;
|
||||||
|
// Make a POST request to the server to authenticate the user
|
||||||
|
fetch('http://localhost:3000/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ username: username, password: password })
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
// Authentication successful
|
||||||
|
console.log('User authenticated successfully');
|
||||||
|
// Redirect the user to the authenticated area or perform other actions
|
||||||
|
} else {
|
||||||
|
// Authentication failed
|
||||||
|
console.error('Error authenticating user');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error authenticating user', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function showRegisterForm(){
|
||||||
|
const registerForm = document.getElementById('registerForm')
|
||||||
|
registerForm.style.display = 'block'
|
||||||
|
const loginForm = document.getElementById('loginForm')
|
||||||
|
loginForm.style.display = 'none'
|
||||||
|
}
|
0
ruscoapp/public/marker.js
Normal file
41
ruscoapp/public/register.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// register.js
|
||||||
|
document.getElementById('registerForm').addEventListener('submit', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if(event.submitter.id == 'showLoginForm') {
|
||||||
|
return showLoginModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var username = document.getElementById('username').value;
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
const data = { username: username, password: password };
|
||||||
|
|
||||||
|
// Make a POST request to the server to register the new user
|
||||||
|
fetch('http://localhost:3000/register', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
// Registration successful
|
||||||
|
console.log('User registered successfully');
|
||||||
|
} else {
|
||||||
|
// Registration failed
|
||||||
|
console.error('Error registering new user');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error registering new user', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function showLoginModal(){
|
||||||
|
const loginForm = document.getElementById('loginForm')
|
||||||
|
loginForm.style.display = 'block'
|
||||||
|
const registerForm = document.getElementById('registerForm')
|
||||||
|
registerForm.style.display = 'none'
|
||||||
|
}
|
35
ruscoapp/public/rusco.geojson
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"Nome": "Televisore",
|
||||||
|
"Descrizione": "estitcamente messo bene",
|
||||||
|
"Foto": "foto/tv.jpg"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
11.33,
|
||||||
|
44.48
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"Nome": "Cyclette",
|
||||||
|
"Descrizione": "Manca pedale sx",
|
||||||
|
"Foto": "foto/cyclette.jpg"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
11.36,
|
||||||
|
44.48
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
23
ruscoapp/public/unused.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//LOGICA BTN
|
||||||
|
function preparaDOM () {
|
||||||
|
const button = document.querySelector('#PMaggiore')
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
//const risposta = prompt("Dammi coordinates");
|
||||||
|
const puntoNuovo = {
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
Nome: 'Coors Field',
|
||||||
|
Descrizione: 'Baseball Stadium'
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: piazzaMaggiore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//PUSH NUOVECOORD
|
||||||
|
points.push(puntoNuovo)
|
||||||
|
//RELOAD JSON
|
||||||
|
L.geoJSON(points).addTo(map)
|
||||||
|
button.innerHTML = "Aggiungi piu' ombra"
|
||||||
|
})
|
||||||
|
}
|
122
ruscoapp/server.js
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
const express = require('express')
|
||||||
|
const sqlite3 = require('sqlite3').verbose()
|
||||||
|
const path = require('path')
|
||||||
|
const bcrypt = require('crypto')
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
const port = 3000
|
||||||
|
|
||||||
|
// Create a new SQLite database in memory
|
||||||
|
const db = new sqlite3.Database('ruscodb')
|
||||||
|
|
||||||
|
// Create a table to store data
|
||||||
|
db.serialize(() => {
|
||||||
|
db.get(
|
||||||
|
`SELECT name FROM sqlite_master WHERE type='table' AND name='ruschi';`,
|
||||||
|
(err, row) => {
|
||||||
|
if (!row) {
|
||||||
|
db.run(
|
||||||
|
'CREATE TABLE ruschi (id INTEGER PRIMARY KEY, type TEXT, name TEXT, description TEXT, image_url TEXT, latitude REAL, longitude REAL)'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')))
|
||||||
|
app.use(express.json())
|
||||||
|
// app.get('/', (req, res) => {
|
||||||
|
// res.sendFile('index.html')
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Insert a new item into the database
|
||||||
|
app.post('/addRuschi', (req, res) => {
|
||||||
|
const { name, description, imageUrl, latitude, longitude } = req.body
|
||||||
|
const type = 'bho'
|
||||||
|
db.run(
|
||||||
|
'INSERT INTO ruschi (type, name, description, image_url, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?)',
|
||||||
|
[type, name, description, imageUrl, latitude, longitude],
|
||||||
|
function (err) {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err.message)
|
||||||
|
}
|
||||||
|
console.log(`A row has been inserted with rowid ${this.lastID}`)
|
||||||
|
res.send(`Item added with ID: ${this.lastID}`)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Retrieve all items from the database
|
||||||
|
app.get('/getRuschi', (req, res) => {
|
||||||
|
db.all('SELECT * FROM ruschi', [], (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err.message)
|
||||||
|
}
|
||||||
|
let ruschi = []
|
||||||
|
rows.forEach(rusco => {
|
||||||
|
const coordinates = { latitude: rusco.latitude, longitude: rusco.longitude }
|
||||||
|
const marker = {
|
||||||
|
type: "Feature",
|
||||||
|
properties: {
|
||||||
|
name: rusco.name,
|
||||||
|
description: rusco.description,
|
||||||
|
image_url: rusco.image_url,
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: rusco.type,
|
||||||
|
coordinates: coordinates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ruschi.push(marker)
|
||||||
|
})
|
||||||
|
return res.json(ruschi)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/login', (req, res) => {
|
||||||
|
const username = req.body.username
|
||||||
|
const password = req.body.password
|
||||||
|
const hashedPassword = bcrypt
|
||||||
|
.createHash('sha256')
|
||||||
|
.update(password)
|
||||||
|
.digest('base64') //.digest('base64');
|
||||||
|
|
||||||
|
db.all(
|
||||||
|
'SELECT * FROM users WHERE username = ? AND password = ?',
|
||||||
|
[username, hashedPassword],
|
||||||
|
(err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err.message)
|
||||||
|
}
|
||||||
|
if (rows.length == 1) {
|
||||||
|
return res.json('Logged in')
|
||||||
|
}
|
||||||
|
return res.json('Incorrect username or password')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/register', (req, res) => {
|
||||||
|
console.log(req.body)
|
||||||
|
const username = req.body.username
|
||||||
|
const password = req.body.password
|
||||||
|
const hashedPassword = bcrypt
|
||||||
|
.createHash('sha256')
|
||||||
|
.update(password)
|
||||||
|
.digest('base64') //.digest('base64');
|
||||||
|
db.run(
|
||||||
|
'insert into users (username, password) VALUES (?, ?)',
|
||||||
|
[username, hashedPassword],
|
||||||
|
(err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err.message)
|
||||||
|
}
|
||||||
|
res.json('OK')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server is running on http://localhost:${port}`)
|
||||||
|
})
|
6
ruscoapp/sqlite_init.sh
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
sqlite3 ruscodb "create table users (username TEXT, password TEXT);"
|
||||||
|
sqlite3 ruscodb "insert into users (username, password) VALUES ('gabibbo','test');"
|
||||||
|
sqlite3 ruscodb "create table ruschi (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, nome TEXT, descrizione VARCHAR, foto TEXT, lat REAL, lng REAL);"
|
||||||
|
sqlite3 ruscodb "INSERT INTO ruschi (type, nome, descrizione, foto, lat, lng) VALUES ('random_type', 'random_nome', 'random_descrizione', 'random_foto.jpg', RANDOM(), RANDOM());"
|
||||||
|
|
Before Width: | Height: | Size: 1.7 MiB |
|
@ -1,33 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
# Script per aggiornare ruscomap
|
|
||||||
# nano /var/www/html/leaflet/ruscomap/AggiornaRuscoMap.sh
|
|
||||||
ruscomap_dir="/var/www/html/leaflet/ruscomap"
|
|
||||||
ruscomap_public="/var/www/html/leaflet/ruscomap/public"
|
|
||||||
|
|
||||||
echo -e "\nStoppo ruscomap..."
|
|
||||||
systemctl stop ruscomap.service || echo -e "\nErrore nell'arrestare ruscomap!\n"
|
|
||||||
|
|
||||||
cd "${ruscomap_dir}" || exit 1
|
|
||||||
echo -e "\nEseguo git pull..."
|
|
||||||
git pull || (echo -e "\nErrore git!\n" && exit 1)
|
|
||||||
cd "server" || exit 1
|
|
||||||
npm ci
|
|
||||||
systemctl start ruscomap.service
|
|
||||||
|
|
||||||
echo -e "\nDo permessi www-data..."
|
|
||||||
chown -R www-data:www-data "$ruscomap_public" || echo -e "\nErrore nel dare i permessi a $ruscomap_public \n"
|
|
||||||
|
|
||||||
echo -e "\nrestarto apache e ruscomap"...
|
|
||||||
systemctl restart apache2.service && echo "apache restart"
|
|
||||||
systemctl start ruscomap.service && echo "rusco restart"
|
|
||||||
|
|
||||||
echo -e "\nDo permessi di esecuzione allo script di aggiornamento.."
|
|
||||||
chmod +x /var/www/html/leaflet/ruscomap/script/AggiornaRuscoMap.sh || echo -e "\nErrore nel dare i permessi a /var/www/html/leaflet/ruscomap/script/AggiornaRuscoMap.sh\n"
|
|
||||||
|
|
||||||
echo -e "Do permessi di esecuzione allo script pulisci_vecchio_rusco.sh.."
|
|
||||||
chmod +x /var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh || echo -e "\nErrore nel dare i permessi a /var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh\n"
|
|
||||||
|
|
||||||
echo -e "\nAggiornamento completato!\n"
|
|
|
@ -1,24 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script per cercare una parola (input utente) nella colonna "name" e/o "description"
|
|
||||||
|
|
||||||
#Imposta credenziali
|
|
||||||
DB_USER=$(jq -r '.db.user' ../config/default.json)
|
|
||||||
DB_PASS=$(jq -r '.db.password' ../server/config/default.json)
|
|
||||||
DB_NAME=$(jq -r '.db.database' ../server/config/default.json)
|
|
||||||
TABLE_NAME=$(jq -r '.db.table' ../server/config/default.json)
|
|
||||||
|
|
||||||
# Controlla se DB_USER è "myusername"
|
|
||||||
if [ "$DB_USER" == "myusername" ]; then
|
|
||||||
echo -e "\nDevi impostare nome utente e password per usare lo script"
|
|
||||||
echo -e "editalo con nano cerca_rusco.sh"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Stampa records che nella colonna "name" e/o "description" hanno la parola $KEYWORD
|
|
||||||
mysql -u "$DB_USER" \
|
|
||||||
-p"$DB_PASS" \
|
|
||||||
"$DB_NAME" \
|
|
||||||
-e "SELECT * FROM '$TABLE_NAME' \
|
|
||||||
WHERE name LIKE '$KEYWORD' \
|
|
||||||
OR description LIKE '$KEYWORD';"
|
|
|
@ -1,23 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script per cancellare tutti i record della table "markers"
|
|
||||||
|
|
||||||
# Imposta credenziali
|
|
||||||
DB_USER=$(jq -r '.db.user' ../server/config/default.json)
|
|
||||||
DB_PASS=$(jq -r '.db.password' ../server/config/default.json)
|
|
||||||
|
|
||||||
# Controlla se DB_USER è "myusername"
|
|
||||||
if [ "$DB_USER" == "myusername" ]; then
|
|
||||||
echo -e "1nDevi impostare nome utente e password per usare lo script"
|
|
||||||
echo -e "editalo con nano pulisci_vecchio_rusco.sh"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Connetti al db e cancella la table markers
|
|
||||||
mariadb -u "$DB_USER" -p"$DB_PASS" <<EOF
|
|
||||||
USE ruscomap;
|
|
||||||
TRUNCATE TABLE markers;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# elimina tutte le immagini caricate
|
|
||||||
find ../uploads -type f -exec rm {} \;
|
|
|
@ -1,33 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#set -x
|
|
||||||
# Prendi credenziali db e tabella
|
|
||||||
DB_USER=$(jq -r '.db.user' ../server/config/default.json)
|
|
||||||
DB_PASS=$(jq -r '.db.password' ../server/config/default.json)
|
|
||||||
DB_NAME=$(jq -r '.db.database' ../server/config/default.json)
|
|
||||||
TABLE_NAME=$(jq -r '.db.table' ../server/config/default.json)
|
|
||||||
|
|
||||||
# Valori coords market ricicla
|
|
||||||
coordinates=(
|
|
||||||
"POINT(11.386956274509432 44.47601517125007)"
|
|
||||||
"POINT(11.373899281024935 44.484269124276224)"
|
|
||||||
"POINT(11.366094052791597 44.498236752697885)"
|
|
||||||
"POINT(11.352428197860718 44.51198490203542)"
|
|
||||||
"POINT(11.329773100000000 44.51429310000000)"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Loop inserirmento ricicla
|
|
||||||
for i in "${coordinates[@]}"; do
|
|
||||||
# Genera dati riciclaq
|
|
||||||
NAME='Ricicla'
|
|
||||||
DESCRIPTION='Alimenti ancora buoni buttati vicino ai cassoneti dei supermercati da subito dopo chiusura. Maggiori info su: riciclabologna.vado.li'
|
|
||||||
FILENAME='riciclaimg'
|
|
||||||
COORDINATE="$i"
|
|
||||||
TS='2016-01-10 21:42:42'
|
|
||||||
|
|
||||||
# SQL command per inserire i dati
|
|
||||||
SQL_COMMAND="INSERT INTO $TABLE_NAME (name, description, filename, coordinate, ts) VALUES ('$NAME', '$DESCRIPTION', '$FILENAME', ST_GeomFromText('$COORDINATE'), '$TS');"
|
|
||||||
|
|
||||||
# Esegue inserimento
|
|
||||||
mysql -u "$DB_USER" -p"$DB_PASS" -D "$DB_NAME" -e "$SQL_COMMAND"
|
|
||||||
done
|
|
|
@ -1,54 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script per cancellare tutti i record della table "markers" più vecchi di 24h (manuale)
|
|
||||||
|
|
||||||
# Imposta credenziali
|
|
||||||
DB_USER=$(jq -r '.db.user' ../server/config/default.json)
|
|
||||||
DB_PASS=$(jq -r '.db.password' ../server/config/default.json)
|
|
||||||
DB_NAME=$(jq -r '.db.database' ../server/config/default.json)
|
|
||||||
TABLE_NAME=$(jq -r '.db.table' ../server/config/default.json)
|
|
||||||
|
|
||||||
# Controlla se DB_USER è "myusername"
|
|
||||||
if [ "$DB_USER" == "myusername" ]; then
|
|
||||||
echo -e "1nDevi impostare nome utente e password per usare lo script"
|
|
||||||
echo -e "editalo con nano pulisci_vecchio_rusco.sh"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Mostra dati impostati
|
|
||||||
echo -e "\nDati impostati:"
|
|
||||||
echo -e "$DB_USER"
|
|
||||||
echo -e "$DB_PASS"
|
|
||||||
echo -e "$DB_NAME"
|
|
||||||
echo -e "$TABLE_NAME\n"
|
|
||||||
|
|
||||||
# Chiedi all'utente se i dati sono giusti
|
|
||||||
read -p "I dati sono giusti? Vuoi continuare? (y/yes/s/si): " user_input
|
|
||||||
|
|
||||||
# Converti l'input in minuscolo
|
|
||||||
user_input_lower=$(echo "$user_input" | tr '[:upper:]' '[:lower:]')
|
|
||||||
|
|
||||||
# Controlla se l'input è uno dei valori accettabili
|
|
||||||
if [[ "$user_input_lower" == "y" || "$user_input_lower" == "yes" || "$user_input_lower" == "s" || "$user_input_lower" == "si" ]]; then
|
|
||||||
|
|
||||||
echo -e "Cancello la table $TABLE_NAME..."
|
|
||||||
|
|
||||||
# Prendi l'ora e data meno 24 ore
|
|
||||||
TIME_THRESHOLD=$(date -d '24 hours ago' '+%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
# comando sql che cancella i record piu vecchi di 24h
|
|
||||||
SQL_COMMAND="DELETE FROM $TABLE_NAME WHERE ts < '$TIME_THRESHOLD';"
|
|
||||||
|
|
||||||
# esegue il comando Execute the SQL command
|
|
||||||
mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$SQL_COMMAND"
|
|
||||||
|
|
||||||
# elimina tutte le immagini caricate più di 24h fa
|
|
||||||
find ../uploads -type f -mmin +1440 -exec rm {} \;
|
|
||||||
|
|
||||||
# check del comando
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "Rusco più vecchi di 24h cancellato."
|
|
||||||
else
|
|
||||||
echo "\nErrore!\n"
|
|
||||||
fi
|
|
||||||
fi
|
|
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script per cancellare tutti i record della table "markers" più vecchi di 24h (automatico)
|
|
||||||
|
|
||||||
#Imposta credenziali
|
|
||||||
DB_USER=$(jq -r '.db.user' ../server/config/default.json)
|
|
||||||
DB_PASS=$(jq -r '.db.password' ../server/config/default.json)
|
|
||||||
DB_NAME=$(jq -r '.db.database' ../server/config/default.json)
|
|
||||||
TABLE_NAME=$(jq -r '.db.table' ../server/config/default.json)
|
|
||||||
|
|
||||||
# Prendi l'ora e data meno 24 ore
|
|
||||||
TIME_THRESHOLD=$(date -d '24 hours ago' '+%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
# comando sql che cancella i record piu vecchi di 24h
|
|
||||||
SQL_COMMAND="DELETE FROM $TABLE_NAME WHERE ts < '$TIME_THRESHOLD';"
|
|
||||||
|
|
||||||
# esegue il comando Execute the SQL command
|
|
||||||
mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$SQL_COMMAND"
|
|
||||||
|
|
||||||
# elimina tutte le immagini caricate più di 24h fa
|
|
||||||
find ../server/public/uploads/ -type f -mmin +1440 -exec rm {} \;
|
|
||||||
|
|
||||||
# check del comando
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "Rusco più vecchi di 24h cancellato."
|
|
||||||
else
|
|
||||||
echo "\ERRORE!\n"
|
|
||||||
fi
|
|
|
@ -1,10 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd /var/www/html/leaflet/ruscomap/server/public/uploads
|
|
||||||
|
|
||||||
for file in *; do
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
# mv "$file" "${file}.jpeg" # spacca tutte le immagini
|
|
||||||
exiftool -all= * -overwrite_original
|
|
||||||
fi
|
|
||||||
done
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"app": {
|
|
||||||
"port": "3232",
|
|
||||||
"upload": "public/uploads/"
|
|
||||||
},
|
|
||||||
"db": {
|
|
||||||
"host": "127.0.0.1",
|
|
||||||
"user": "ruscone",
|
|
||||||
"database": "ruscomap",
|
|
||||||
"password": "password",
|
|
||||||
"table": "markers"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"app": {
|
|
||||||
"port": "3000",
|
|
||||||
"upload": "uploads/"
|
|
||||||
},
|
|
||||||
"db": {
|
|
||||||
"host": "localhost",
|
|
||||||
"user": "ruser",
|
|
||||||
"database": "ruscodb",
|
|
||||||
"password": "password",
|
|
||||||
"table": "markers"
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
const config = require("config");
|
|
||||||
const mysql = require("mysql");
|
|
||||||
|
|
||||||
const pool = mysql.createPool({
|
|
||||||
host: config.get("db.host"),
|
|
||||||
user: config.get("db.user"),
|
|
||||||
password: config.get("db.password"),
|
|
||||||
database: config.get("db.database"),
|
|
||||||
});
|
|
||||||
|
|
||||||
function addMarker(marker) {
|
|
||||||
const insertQuery = "INSERT INTO markers VALUES (?,?,?,POINT(?,?),?)";
|
|
||||||
const date = new Date();
|
|
||||||
|
|
||||||
const query = mysql.format(insertQuery, [
|
|
||||||
marker.name,
|
|
||||||
marker.description,
|
|
||||||
marker.filename,
|
|
||||||
marker.long,
|
|
||||||
marker.lat,
|
|
||||||
date,
|
|
||||||
]);
|
|
||||||
|
|
||||||
pool.query(query, (err, response) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// rows added
|
|
||||||
console.log(response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAllMarkers(callback) {
|
|
||||||
pool.getConnection((err, connection) => {
|
|
||||||
if (err) throw err;
|
|
||||||
connection.query("SELECT * from markers", (err, rows) => {
|
|
||||||
connection.release(); // return the connection to pool
|
|
||||||
if (err) throw err;
|
|
||||||
callback(rows);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUpdatedMarkers(fromDate, callback) {
|
|
||||||
pool.getConnection((err, connection) => {
|
|
||||||
if (err) throw err;
|
|
||||||
let selectQuery = "SELECT * FROM markers mrk WHERE mrk.ts >= ?";
|
|
||||||
let query = mysql.format(selectQuery, fromDate);
|
|
||||||
connection.query(query, (err, rows) => {
|
|
||||||
connection.release(); // return the connection to pool
|
|
||||||
if (err) throw err;
|
|
||||||
callback(rows);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
addMarker,
|
|
||||||
getAllMarkers,
|
|
||||||
getUpdatedMarkers,
|
|
||||||
};
|
|
|
@ -1,88 +0,0 @@
|
||||||
const express = require("express");
|
|
||||||
const multer = require("multer");
|
|
||||||
const config = require("config");
|
|
||||||
const { version } = require("./package.json");
|
|
||||||
|
|
||||||
const dbHandler = require("./dbHandler.js");
|
|
||||||
const upload = multer({ dest: config.get("app.upload") });
|
|
||||||
|
|
||||||
const PUBLIC_PATH = `${__dirname}/../public`;
|
|
||||||
|
|
||||||
let server = undefined;
|
|
||||||
|
|
||||||
const configureRoutes = (app) => {
|
|
||||||
app.get("/", (req, res) => {
|
|
||||||
res.sendFile(`${PUBLIC_PATH}/index.html`);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/uploadMarker", upload.single("image"), (req, res) => {
|
|
||||||
const data = req.body;
|
|
||||||
image = req.file;
|
|
||||||
|
|
||||||
// Extract marker data
|
|
||||||
const newMarker = {
|
|
||||||
name: data.name,
|
|
||||||
description: data.description,
|
|
||||||
filename: image.filename,
|
|
||||||
long: data.long,
|
|
||||||
lat: data.lat,
|
|
||||||
};
|
|
||||||
// Add marker to db
|
|
||||||
dbHandler.addMarker(newMarker);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/fetchMarkers", (req, res) => {
|
|
||||||
dbHandler.getAllMarkers((rows) => {
|
|
||||||
res.status(200).json(rows);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/updateMarkers", (req, res) => {
|
|
||||||
const data = req.query;
|
|
||||||
|
|
||||||
// data.fromDate comes as a string so we need to parse it before creating a date object based on it
|
|
||||||
dbHandler.getUpdatedMarkers(new Date(Number(data.fromDate)), (rows) => {
|
|
||||||
res.status(200).json(rows);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/version", (req, res) => {
|
|
||||||
res.json({ version });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const configureExpress = () => {
|
|
||||||
const app = express();
|
|
||||||
const port = config.get("app.port");
|
|
||||||
|
|
||||||
app.use(express.static(PUBLIC_PATH));
|
|
||||||
app.use("/imgs", express.static(config.get("app.upload")));
|
|
||||||
app.use(express.json()); // for json
|
|
||||||
app.use(
|
|
||||||
express.urlencoded({
|
|
||||||
extended: true,
|
|
||||||
limit: "12MB",
|
|
||||||
parameterLimit: 100000,
|
|
||||||
})
|
|
||||||
); // support encoded bodies
|
|
||||||
|
|
||||||
configureRoutes(app);
|
|
||||||
|
|
||||||
server = app.listen(port, "0.0.0.0", () => {
|
|
||||||
console.log(`Example app listening on port ${port}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
return app;
|
|
||||||
};
|
|
||||||
|
|
||||||
const main = () => {
|
|
||||||
process.on("SIGINT", () => {
|
|
||||||
server.close(() => {
|
|
||||||
console.log("Successfully closed HTTP Server.");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
configureExpress();
|
|
||||||
};
|
|
||||||
|
|
||||||
main();
|
|
2174
server/package-lock.json
generated
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"name": "ruscomap",
|
|
||||||
"version": "0.8.1",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"start": "node server/index.js",
|
|
||||||
"dev": "nodemon server/index.js"
|
|
||||||
},
|
|
||||||
"author": "HacklabBO",
|
|
||||||
"license": "UNLICENSED",
|
|
||||||
"dependencies": {
|
|
||||||
"config": "^3.3.12",
|
|
||||||
"express": "^4.21.0",
|
|
||||||
"leaflet": "^1.9.4",
|
|
||||||
"leaflet.locatecontrol": "^0.81.1",
|
|
||||||
"multer": "^1.4.5-lts.1",
|
|
||||||
"mysql": "^2.18.1",
|
|
||||||
"nodemon": "^3.1.7",
|
|
||||||
"sqlite": "^5.1.1"
|
|
||||||
}
|
|
||||||
}
|
|
31
tutorial.md
|
@ -1,31 +0,0 @@
|
||||||
# RuscoMap
|
|
||||||
|
|
||||||
RuscoMap è una mappa della propria città dove utenti in anonimo possono inserire dei marker con nome, descrizione e foto dell'oggetto abbandonato, segnalandolo a tutti i visitatori della mappa._
|
|
||||||
|
|
||||||
Si può trovare o inserire la qualunque purchè ci sia una vaga speranza di riutilizzo, trasformazione o riparazione.
|
|
||||||
|
|
||||||
Sulla falsa riga del "_te lo regalo se vieni a prenderlo_", questo è più il "_segnalo che c'è sta roba lì, è tua se te la vai a prendere_"
|
|
||||||
|
|
||||||
|
|
||||||
### Navigazione
|
|
||||||
|
|
||||||
Quando sei sulla mappa, puoi liberamente curiosare tra gli oggetti inseriti
|
|
||||||
oppure cercare con il form $SOMEWHERE una parola chiave
|
|
||||||
esempio ricerca: divano. Spariranno tutti i marker rimanendo solo quelli che nel nome o nella descrizione contengono la parola "divano".
|
|
||||||
|
|
||||||
### Inserimento
|
|
||||||
|
|
||||||
Cliccando il pulsante in alto a destra (icona marker blu) entri in modalità inserimento.
|
|
||||||
|
|
||||||
A questo punto cliccando su un punto della mappa inserisci la posizione del nuovo marker.
|
|
||||||
|
|
||||||
Si aprirà un form dove inserire nome dell'oggetto, una breve descrizione e una foto.
|
|
||||||
|
|
||||||
Cliccando "Aggiungi marker" il nuovo oggetto comparirà automagicamente sula mappa.
|
|
||||||
|
|
||||||
```
|
|
||||||
coordinate: { x: formInputCoordX.value, y: formInputCoordY.value },
|
|
||||||
name: '',
|
|
||||||
description: "Compila il form per aggiungere un marker qui. Oppure annulla l'inserimento del marker cliccando sulla X in alto a destra",
|
|
||||||
filename: null,
|
|
||||||
```
|
|