Compare commits

...

No commits in common. "Production" and "master" have entirely different histories.

74 changed files with 3597 additions and 33480 deletions

18
.editorconfig Normal file
View 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
View 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
View 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
View file

@ -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
View file

@ -1 +0,0 @@
v20.11.1

438
README.md
View file

@ -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>

View file

@ -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

View file

@ -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
);

View file

@ -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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -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>

File diff suppressed because one or more lines are too long

View file

@ -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 */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -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;
});

View file

@ -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,
];
}

View file

@ -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);

View file

@ -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();

View file

@ -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:
'&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
}).addTo(map);
L.control.locate().addTo(map);
return map;
}

View file

@ -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);
}

View file

@ -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
View 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

File diff suppressed because it is too large Load diff

16
ruscoapp/package.json Normal file
View 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"
}
}

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,3 @@
#!/bin/bash
mat2 --inplace *

BIN
ruscoapp/public/foto/tv.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 696 B

View file

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 618 B

49
ruscoapp/public/index.css Normal file
View 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
View 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
View 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: "&copy; 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);

File diff suppressed because it is too large Load diff

39
ruscoapp/public/login.js Normal file
View 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'
}

View file

View 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'
}

View 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
View 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"
})
}

Binary file not shown.

122
ruscoapp/server.js Normal file
View 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
View 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());"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -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"

View file

@ -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';"

View file

@ -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 {} \;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,13 +0,0 @@
{
"app": {
"port": "3232",
"upload": "public/uploads/"
},
"db": {
"host": "127.0.0.1",
"user": "ruscone",
"database": "ruscomap",
"password": "password",
"table": "markers"
}
}

View file

@ -1,13 +0,0 @@
{
"app": {
"port": "3000",
"upload": "uploads/"
},
"db": {
"host": "localhost",
"user": "ruser",
"database": "ruscodb",
"password": "password",
"table": "markers"
},
}

View file

@ -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,
};

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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"
}
}

View file

@ -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,
```