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/
|
||||
uploads/
|
||||
config/default.json
|
||||
.vscode/
|
||||
db_data/
|
||||
/.phpunit.cache
|
||||
/**/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/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
|
438
README.md
|
@ -1,371 +1,85 @@
|
|||
# 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._
|
||||
<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
|
||||
```
|
||||
# Rusco Map
|
||||
|
||||
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>
|
||||
|
||||
|
||||
## 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)
|
||||
|
||||
##### Imposta lo script su cron per essere eseguito ogni 24h
|
||||
|
||||
```
|
||||
# Per eseguire tutti i giorni a mezzanotte lo script che elimina tutti i marker più vecchi di 24h:
|
||||
|
||||
# Entra in modalità edit su cron:
|
||||
crontab -e
|
||||
|
||||
# Edita il file aggiungendo la riga:
|
||||
0 0 * * * /var/www/html/leaflet/ruscomap/script/pulisci_vecchio_rusco.sh
|
||||
|
||||
# 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';
|
||||
```
|
||||
## FrontEnd
|
||||
#### 1) Ricerca per titolo e descrizione, con lista filtrati dei marker e visualizzazione su mappa
|
||||
#### 2) Mappa con lista di marker filtrata o meno
|
||||
#### 3) Inserimento:
|
||||
- Modalita' che nasconde la barra di ricerca
|
||||
- All'inserimento di un marker mostra il form
|
||||
- Modalita' d'inserimento
|
||||
- Mobile: Mirino sulla mappa, premere btn + per conferma e.g. osmand
|
||||
- PC: click sulla mappa
|
||||
- Form con campi dello shapefile con pulsante di conferma
|
||||
#### 4) Login
|
||||
<br>
|
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,
|
||||
```
|