- aggiornato la guida per installare la App

- aggiornato la Guida Completa e Breve di RISO.
- pagina per ricevere i RIS.
- sistemato problema creazione nuovi Circuiti (admin non corretti).
- corretto giro delle email, invitante, invitato e ricezione msg su telegram.
This commit is contained in:
Surya Paolo
2025-11-23 01:13:32 +01:00
parent 5b1f3eafbc
commit 00bdc278d8
23 changed files with 2765 additions and 701 deletions

View File

@@ -66,7 +66,7 @@ db.myelems.insertMany([
"listcards": [],
"list": [],
"__v": 0,
"containerHtml": "<style>\nbody {\n    font-family: Arial, sans-serif;\n    margin: 0;\n    padding: 20px;\n    background-color: #f0f0f0;\n    color: #333;\n}\n\nh1 {\n    color: #0056b3;\n    text-align: center;\n}\n\n\np, li {\n    line-height: 1.6;\n}\n\n\nul {\n    list-style-type: none;\n    padding: 0;\n}\n\n\nli {\n    background-color: #fff !important;\n    margin-bottom: 10px !important;\n    padding: 10px !important;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important; \n}\n\n\na {\n    color: #007bff;\n    text-decoration: none;\n}\n\n\na:hover {\n    text-decoration: underline;\n}\n\n\n.container {\n    max-width: 800px;\n    margin: 0 auto;\n    background-color: #fff;\n    padding: 20px;\n    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n}\n\n\n.strong {\n    font-weight: bold;\n}\n</style>\n\n\n<p><strong>“Abitare gli Iblei”</strong> è una rete aperta che ha lo scopo di riunire tutte quelle persone che vogliono valorizzare e qualificare la vita nel territorio degli Iblei.&nbsp;</p>\n&nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; <p>Chi aderisce alla rete si riconosce in una <strong>Carta dei valori comuni</strong> e usa la rete per scambiare conoscenze, esperienze, risorse e prodotti sviluppati nellambito delle proprie iniziative (profit e non profit) individuali o collettive.</p>\n\n\n&nbsp; &nbsp; <p>Larea territoriale di questa rete è quella dei <strong>Monti Iblei orientali e occidentali</strong> (Noto, Avola, Canicattini, Siracusa, Palazzolo, Buccheri, Ferla, Modica, …).</p>\n\n\n&nbsp; &nbsp; <p>La rete <strong>“Abitare gli Iblei”</strong> offre i seguenti servizi utili per il territorio ed i suoi abitanti, frutto di una costruzione collettiva:</p>\n&nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; <ul>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>1. Mappa delle attività virtuose:</strong> permette di identificare attività pubbliche e private nel territorio che possono essere utili nella vita quotidiana. Queste attività possono riguardare artigiani, produttori o fornitori di servizi di cui almeno un membro della rete conosca la qualità e laffidabilità (agricoltori, falegnami, fabbri, idraulici, imprese edili, strutture ricettive, …). Altre informazioni utili possono riguardare associazioni/istituzioni operanti in vari settori. <strong>Accesso pubblico</strong></li>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>2. Calendario:</strong> permette di accedere ad annunci di eventi utili alla crescita culturale del territorio. La pubblicazione di eventi è riservata ai soli membri della rete che possono presentare iniziative anche di altri organizzatori. <strong>Accesso pubblico</strong></li>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>3. Scambi di servizi, prodotti e ospitalità:</strong> questa funzione è riservata ai soli membri della rete e si realizza attraverso la Rete Italiana scambi orizzontali (RISO). <strong>Accesso riservato</strong></li>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>4. Segnalazione di pericoli per il territorio:</strong> attraverso questa mappa è possibile segnalare incendi, immondizia abbandonata, discariche abusive, fonti di inquinamento per corsi dacqua e spiagge, presenza di inquinamento nellaria, … <strong>Accesso riservato</strong></li>\n&nbsp; &nbsp; </ul>\n&nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; <p>Se vuoi aderire alla rete puoi richiederne la registrazione utilizzando questo Link <a href=\"#\"><strong>(Pagina in Costruzione)</strong></a>.</p>\n\n",
"containerHtml": "<style>\nbody {\n    font-family: Arial, sans-serif;\n    margin: 0;\n    padding: 20px;\n    background-color: #f0f0f0;\n    color: #333;\n}\n\nh1 {\n    color: #0056b3;\n    text-align: center;\n}\n\n\np, li {\n    line-height: 1.6;\n}\n\n\nul {\n    list-style-type: none;\n    padding: 0;\n}\n\n\nli {\n    background-color: #fff !important;\n    margin-bottom: 10px !important;\n    padding: 10px !important;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important; \n}\n\n\na {\n    color: #007bff;\n    text-decoration: none;\n}\n\n\na:hover {\n    text-decoration: underline;\n}\n\n\n.container {\n    max-width: 800px;\n    margin: 0 auto;\n    background-color: #fff;\n    padding: 20px;\n    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n}\n\n\n.strong {\n    font-weight: bold;\n}\n</style>\n\n\n<p><strong>“Abitare gli Iblei”</strong> è una rete aperta che ha lo scopo di riunire tutte quelle persone che vogliono valorizzare e qualificare la vita nel territorio degli Iblei.&nbsp;</p>\n&nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; <p>Chi aderisce alla rete si riconosce in una <strong>Carta dei valori comuni</strong> e usa la rete per scambiare conoscenze, esperienze, risorse e prodotti sviluppati nellambito delle proprie iniziative (profit e non profit) individuali o collettive.</p>\n\n\n&nbsp; &nbsp; <p>Larea territoriale di questa rete è quella dei <strong>Monti Iblei orientali e occidentali</strong> (Noto, Avola, Canicattini, Siracusa, Palazzolo, Buccheri, Ferla, Modica, …).</p>\n\n\n&nbsp; &nbsp; <p>La rete <strong>“Abitare gli Iblei”</strong> offre i seguenti servizi utili per il territorio ed i suoi abitanti, frutto di una costruzione collettiva:</p>\n&nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; <ul>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>1. Mappa delle attività virtuose:</strong> permette di identificare attività pubbliche e private nel territorio che possono essere utili nella vita quotidiana. Queste attività possono riguardare artigiani, produttori o fornitori di servizi di cui almeno un membro della rete conosca la qualità e laffidabilità (agricoltori, falegnami, fabbri, idraulici, imprese edili, strutture ricettive, …). Altre informazioni utili possono riguardare associazioni/istituzioni operanti in vari settori. <strong>Accesso pubblico</strong></li>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>2. Calendario:</strong> permette di accedere ad annunci di eventi utili alla crescita culturale del territorio. La pubblicazione di eventi è riservata ai soli membri della rete che possono presentare iniziative anche di altri organizzatori. <strong>Accesso pubblico</strong></li>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>3. Scambi di servizi, prodotti e ospitalità:</strong> questa funzione è riservata ai soli membri della rete e si realizza attraverso la Rete Italiana scambio orizzontale (RISO). <strong>Accesso riservato</strong></li>\n&nbsp; &nbsp; &nbsp; &nbsp; <li><strong>4. Segnalazione di pericoli per il territorio:</strong> attraverso questa mappa è possibile segnalare incendi, immondizia abbandonata, discariche abusive, fonti di inquinamento per corsi dacqua e spiagge, presenza di inquinamento nellaria, … <strong>Accesso riservato</strong></li>\n&nbsp; &nbsp; </ul>\n&nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; <p>Se vuoi aderire alla rete puoi richiederne la registrazione utilizzando questo Link <a href=\"#\"><strong>(Pagina in Costruzione)</strong></a>.</p>\n\n",
"anim": {
"_id": new ObjectId("66db393e3b885ccdfaed28d6"),
"name": "",

View File

@@ -423,16 +423,13 @@ html(lang="it")
.email-header
- var baseimg = baseurl + '/';
img.header-logo(src=baseimg+"images/logo.png" alt=nomeapp || 'Logo')
.welcome-icon 💚
h1 Benvenuti nella comunità RISO
p
strong #{name || username || 'Tu'}
| #{name || username ? ',' : ''} sei ufficialmente parte di qualcosa di speciale!
h1 Benvenuto/a #{name || username} nella community RISO! 💚
.email-body
.welcome-message
h2 🎉 Il tuo invitante #{nomeInvitante} ti ha ammesso!
p Sei ora un membro attivo della Rete Italiana di Scambio Orizzontale
if ammessoUtente
h2 🎉 Il tuo invitante #{nomeInvitante} ti ha ammesso!
p Sei ora un membro della Rete Italiana di Scambio Orizzontale
p Inizia subito a scoprire beni, servizi e ospitalità nella tua comunità territoriale
.intro-text
@@ -444,6 +441,37 @@ html(lang="it")
strong un'economia più umana e solidale
| .
.next-steps
.next-steps-title 🎯 I tuoi primi passi nella community RISO
.step-item
.step-number 1
.step-content
h3 ✅ Completa il tuo profilo
p Collega il tuo profilo a Telegram, inserisci la tua Provincia ed accedi ai Circuiti Territoriali per poter iniziare ad usare i RIS. Un profilo completo aiuta gli altri membri a conoscerti meglio!
.step-item
.step-number 2
.step-content
h3 🔍 Esplora gli annunci
p Scopri cosa offrono gli altri membri nella tua area. Potresti trovare esattamente ciò che cerchi!
.step-item
.step-number 3
.step-content
h3 📢 Pubblica il tuo primo annuncio
p Cosa puoi offrire? Beni, servizi o ospitalità - ogni contributo arricchisce la comunità. Ricorda di includere come strumento di scambio il RIS e sperimentalo da subito!
.step-item
.step-number 4
.step-content
h3 💬 Unisciti al gruppo territoriale
p Partecipa alle conversazioni, agli eventi e alle iniziative della tua comunità locale sulle chat Telegram di RISO
.cta-section
.cta-title 🚀 Accedi e inizia il tuo viaggio RISO
.cta-subtitle Scegli come vuoi accedere alla piattaforma
.credentials-box
.credentials-title 📋 I tuoi dati di accesso
@@ -465,10 +493,6 @@ html(lang="it")
br
a(href=forgetpwd target="_blank") Hai dimenticato la password?
.cta-section
.cta-title 🚀 Accedi e inizia il tuo viaggio RISO
.cta-subtitle Scegli come vuoi accedere alla piattaforma
if strlinksito
.cta-buttons-wrapper
a.cta-button(href=strlinksito target="_blank")
@@ -483,33 +507,6 @@ html(lang="it")
span.button-icon 📖
| Leggi la Guida
.next-steps
.next-steps-title 🎯 I tuoi primi passi nella comunità RISO
.step-item
.step-number 1
.step-content
h3 ✅ Completa il tuo profilo
p Aggiungi una foto, descrivi chi sei e cosa ti appassiona. Un profilo completo aiuta gli altri membri a conoscerti meglio!
.step-item
.step-number 2
.step-content
h3 📢 Pubblica il tuo primo annuncio
p Cosa puoi offrire? Beni, servizi o ospitalità - ogni contributo arricchisce la comunità. Ricorda di includere come strumento di scambio il RIS!
.step-item
.step-number 3
.step-content
h3 🔍 Esplora gli annunci
p Scopri cosa offrono gli altri membri nella tua area. Potresti trovare esattamente ciò che cerchi!
.step-item
.step-number 4
.step-content
h3 💬 Unisciti al gruppo territoriale
p Partecipa alle conversazioni, agli eventi e alle iniziative della tua comunità locale sulle chat Telegram di RISO
.info-box
p
strong 💰 Cos'è il RIS?
@@ -526,6 +523,7 @@ html(lang="it")
strong sei un membro attivo
| di una comunità che crede nella solidarietà e nella condivisione!
.email-footer
.divider
p 💚 Benvenuto/a nella famiglia RISO!

View File

@@ -300,7 +300,7 @@ html(lang="it")
.email-container
//- Header
.email-header
img.header-logo(src=baseurl+'/images/logo.png' alt=nomeapp+' - Rete Italiana Scambi Orizzontali')
img.header-logo(src=baseurl+'/images/logo.png' alt=nomeapp+' - Rete Italiana Scambio orizzontale')
h1 🎉 Il tuo invito è stato accettato!
p.subtitle Un nuovo membro si è unito a #{nomeapp}
@@ -318,12 +318,12 @@ html(lang="it")
if emailInvitato
.member-detail
strong Email:
| #{emailInvitato}
a(href=`mailto:${emailInvitato}` style="color: #667eea; text-decoration: none;") #{emailInvitato}
if usernameInvitato
.member-detail
strong Username:
| #{usernameInvitato}
//- Bottone profilo
if usernameInvitato
.buttprof-section
@@ -389,6 +389,6 @@ html(lang="it")
.divider
p Hai ricevuto questa email perché hai invitato #{nomeInvitato} su #{nomeapp} oppure la persona ha usato il tuo username come invitante
p(style="margin-top: 12px; font-size: 12px;")
| #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambi Orizzontali
| #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambio orizzontale
p(style="margin-top: 12px; font-size: 12px;")
| 🍚 Comunità · Fiducia · Scambi Solidali · Sostenibilità

View File

@@ -0,0 +1,471 @@
doctype html
html(lang="it")
head
meta(charset="UTF-8")
meta(name="viewport" content="width=device-width, initial-scale=1.0")
style(type="text/css").
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f5f5f5;
padding: 20px;
line-height: 1.6;
}
.header-logo {
width: 80px;
height: auto;
margin-bottom: 16px;
display: block;
margin-left: auto;
margin-right: auto;
}
.email-container {
max-width: 600px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.email-header {
background: linear-gradient(135deg, #2E7D32 0%, #1B5E20 100%);
color: white;
padding: 40px 24px;
text-align: center;
}
.email-header h1 {
margin: 0 0 8px 0;
font-size: 28px;
font-weight: 600;
}
.email-header p {
margin: 8px 0 0 0;
font-size: 16px;
opacity: 0.95;
line-height: 1.5;
}
.welcome-icon {
font-size: 48px;
margin-bottom: 16px;
}
.email-body {
padding: 24px 20px;
}
.intro-text {
font-size: 16px;
color: #333;
margin-bottom: 20px;
text-align: center;
line-height: 1.7;
padding: 0 10px;
}
.intro-text strong {
color: #2E7D32;
}
.welcome-message {
background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%);
border-left: 4px solid #2E7D32;
border-radius: 8px;
padding: 20px;
margin-bottom: 24px;
text-align: center;
}
.welcome-message h2 {
color: #1B5E20;
font-size: 20px;
margin-bottom: 12px;
font-weight: 600;
}
.welcome-message p {
color: #2E7D32;
font-size: 15px;
line-height: 1.6;
margin: 8px 0;
}
.credentials-box {
background: #f8f9fa;
border-left: 4px solid #2E7D32;
border-radius: 8px;
padding: 16px;
margin-bottom: 24px;
}
.credentials-title {
font-size: 15px;
font-weight: 600;
color: #555;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.credential-row {
display: flex;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #e0e0e0;
}
.credential-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.credential-label {
font-weight: 600;
color: #666;
min-width: 120px;
font-size: 14px;
}
.credential-value {
color: #1a1a1a;
font-size: 15px;
font-weight: 500;
flex: 1;
word-break: break-word;
}
.credential-value a {
color: #2E7D32;
text-decoration: none;
}
.credential-value a:hover {
text-decoration: underline;
}
.cta-section {
margin: 24px 0;
padding: 20px 0;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
}
.cta-title {
font-size: 19px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 8px;
text-align: center;
}
.cta-subtitle {
font-size: 14px;
color: #666;
margin-bottom: 16px;
text-align: center;
line-height: 1.5;
}
.cta-buttons-wrapper {
display: flex;
gap: 12px;
justify-content: center;
align-items: stretch;
flex-wrap: wrap;
margin-top: 16px;
}
.cta-button {
display: inline-block;
padding: 16px 28px;
font-size: 15px;
font-weight: 600;
color: white;
background: linear-gradient(135deg, #2E7D32 0%, #1B5E20 100%);
border-radius: 50px;
text-decoration: none;
box-shadow: 0 4px 12px rgba(46, 125, 50, 0.3);
transition: transform 0.2s, box-shadow 0.2s;
flex: 1;
min-width: 160px;
max-width: 200px;
text-align: center;
}
.cta-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(46, 125, 50, 0.4);
}
.cta-button-secondary {
background: linear-gradient(135deg, #388E3C 0%, #2E7D32 100%);
box-shadow: 0 4px 12px rgba(56, 142, 60, 0.3);
}
.cta-button-secondary:hover {
box-shadow: 0 6px 16px rgba(56, 142, 60, 0.4);
}
.cta-button-tertiary {
background: linear-gradient(135deg, #66BB6A 0%, #4CAF50 100%);
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
}
.cta-button-tertiary:hover {
box-shadow: 0 6px 16px rgba(76, 175, 80, 0.4);
}
.button-icon {
font-size: 18px;
margin-right: 6px;
vertical-align: middle;
}
.next-steps {
background: #fff;
border-radius: 8px;
padding: 20px;
margin: 24px 0;
}
.next-steps-title {
font-size: 18px;
font-weight: 600;
color: #2E7D32;
margin-bottom: 16px;
text-align: center;
}
.step-item {
display: flex;
align-items: flex-start;
padding: 12px;
margin-bottom: 12px;
background: #f8fdf9;
border-radius: 8px;
border-left: 3px solid #4CAF50;
}
.step-number {
background: linear-gradient(135deg, #4CAF50 0%, #388E3C 100%);
color: white;
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 16px;
margin-right: 12px;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-content h3 {
font-size: 16px;
color: #1B5E20;
margin-bottom: 4px;
font-weight: 600;
}
.step-content p {
font-size: 14px;
color: #555;
line-height: 1.5;
margin: 0;
}
.info-box {
background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%);
border-radius: 8px;
padding: 16px;
margin-top: 20px;
text-align: center;
border: 1px solid #A5D6A7;
}
.info-box p {
margin: 0;
color: #1B5E20;
font-size: 14px;
line-height: 1.6;
}
.info-box strong {
color: #2E7D32;
}
.community-note {
background: #fff3e0;
border-left: 4px solid #FF9800;
border-radius: 8px;
padding: 16px;
margin: 20px 0;
text-align: center;
}
.community-note p {
color: #E65100;
font-size: 14px;
margin: 0;
line-height: 1.6;
}
.email-footer {
padding: 20px 16px;
text-align: center;
background: #f8f9fa;
color: #777;
font-size: 13px;
}
.email-footer p {
margin: 6px 0;
}
.divider {
height: 1px;
background: linear-gradient(to right, transparent, #e0e0e0, transparent);
margin: 24px 0;
}
@media only screen and (max-width: 600px) {
body {
padding: 8px;
}
.email-header {
padding: 24px 16px;
}
.email-header h1 {
font-size: 24px;
}
.email-header p {
font-size: 15px;
}
.email-body {
padding: 20px 14px;
}
.welcome-message {
padding: 16px;
}
.credentials-box {
padding: 16px 12px;
}
.credential-row {
flex-direction: column;
align-items: flex-start;
}
.credential-label {
margin-bottom: 4px;
font-size: 13px;
}
.credential-value {
font-size: 14px;
}
.cta-buttons-wrapper {
flex-direction: column;
gap: 12px;
}
.cta-button {
padding: 14px 24px;
font-size: 15px;
width: 100%;
max-width: 100%;
min-width: 100%;
}
.step-item {
padding: 10px;
}
.step-number {
width: 28px;
height: 28px;
font-size: 14px;
}
.step-content h3 {
font-size: 15px;
}
.step-content p {
font-size: 13px;
}
}
body
.email-container
.email-header
- var baseimg = baseurl + '/';
img.header-logo(src=baseimg+"images/logo.png" alt=nomeapp || 'Logo')
h1 💚 #{name || username ? ',' : ''} Benvenuto/a nella piattaforma #{nomeapp} 💚 !
.email-body
.welcome-message
if ammessoUtente
h2 🎉 Il tuo invitante #{nomeInvitante} ti ha ammesso!
p Sei ora un membro attivo della Rete Italiana di Scambio Orizzontale
p Inizia subito a scoprire beni, servizi e ospitalità nella tua comunità territoriale
.credentials-box
.credentials-title 📋 I tuoi dati di accesso
if username
.credential-row
.credential-label Username:
.credential-value #{username}
if emailto
.credential-row
.credential-label Email:
.credential-value #{emailto}
if forgetpwd
.credential-row
.credential-label Password:
.credential-value
| (la password che hai inserito)
br
a(href=forgetpwd target="_blank") Hai dimenticato la password?
.cta-section
.cta-title 🚀 Accedi e inizia il tuo viaggio
.cta-subtitle Scegli come vuoi accedere alla piattaforma
if strlinksito
.cta-buttons-wrapper
a.cta-button(href=strlinksito target="_blank")
span.button-icon 🌐
| Accedi da Web
.email-footer
.divider
p 💚 Benvenuto/a nella famiglia #{nomeapp}!
p(style="margin-top: 8px;") Hai ricevuto questa email perché sei stato/a ammesso/a nella community di #{nomeapp}
p(style="margin-top: 12px; font-size: 12px;")
| © #{new Date().getFullYear()} #{nomeapp}

View File

@@ -0,0 +1 @@
=`Benvenuto in ${nomeapp}`

View File

@@ -282,9 +282,8 @@ html(lang="it")
.email-container
//- Header
.email-header
img.header-logo(src=baseurl+'/images/logo.png' alt=nomeapp+' - Rete Italiana Scambi Orizzontali')
.success-icon 🎉
h1 Il tuo invito è stato accettato!
img.header-logo(src=baseurl+'/images/logo.png' alt=nomeapp+' - Rete Italiana Scambio orizzontale')
h1 🎉 Il tuo invito è stato accettato!
p.subtitle Un nuovo membro si è unito a #{nomeapp}
//- Body
@@ -301,7 +300,7 @@ html(lang="it")
if emailInvitato
.member-detail
strong Email:
| #{emailInvitato}
a(href=`mailto:${emailInvitato}` style="color: #667eea; text-decoration: none;") #{emailInvitato}
if usernameInvitato
.member-detail
strong Username:

View File

@@ -302,9 +302,9 @@ html(lang="it")
.email-container
//- Header
.email-header
img.header-logo(src=baseurl+'/images/logo.png' alt='RISO - Rete Italiana Scambi Orizzontali')
img.header-logo(src=baseurl+'/images/logo.png' alt='RISO - Rete Italiana Scambio orizzontale')
h1 Sei stato invitato ad unirti a #{nomeapp}!
p.subtitle Rete Italiana Scambi Orizzontali
p.subtitle Rete Italiana Scambio orizzontale
//- Body
.email-body
@@ -368,7 +368,7 @@ html(lang="it")
| <strong>Fiducia:</strong> Base del nostro sistema di scambio
.value-item
span.benefit-icon 🚫
| <strong>Non speculativo:</strong> I RIS non hanno valore in sé, si esauriscono negli scambi
| <strong>Non speculativo:</strong> I RIS non hanno valore in sé, ma solo come <strong>unità di misura</strong> degli scambi
.value-item
span.benefit-icon 🌍
| <strong>Sostenibilità:</strong> Promuoviamo stili di vita sani e naturali
@@ -415,7 +415,7 @@ html(lang="it")
.divider
p Hai ricevuto questa email perché #{usernameInvitante || 'un membro della comunità'} ti ha invitato su #{nomeapp}
p(style="margin-top: 12px; font-size: 12px;")
| #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambi Orizzontali
| #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambio orizzontale
p(style="margin-top: 8px; font-size: 11px; color: #999;")
| Se non sei interessato, puoi semplicemente ignorare questa email.
p(style="margin-top: 12px; font-size: 12px;")

View File

@@ -176,7 +176,7 @@ html
tr
td.logoContainer
a(href=baseurl)
img.logo(src=baseurl+"/public/images/logo.png", alt="Logo")
img.logo(src=baseurl+"/images/logo.png", alt="Logo")
if dataemail.templ.testoheadermail_out
tr

View File

@@ -1,37 +1,307 @@
p Ciao #{name},
p Hai ricevuto
strong #{qty} #{symbol}
if groupDestoContoCom
| sul conto
strong #{groupDestoContoCom}
span da parte di #{mittente} in data #{transactionDate} sul
strong #{nomecircuito} !
if causalDest
p <br>
p Descrizione: #{causalDest}
if causale
p <br>
p Commento di #{mittente}: #{causale}
p <br>
p Apri
strong <a href=#{strlinksito} target="_blank">#{nomeapp}</a>&nbsp;
span per vedere il tuo nuovo saldo.
p <br>
p Cordiali Saluti
p Supporto #{nomeapp}
style(type="text/css").
html, body {
padding: 0;
doctype html
html(lang="it")
head
meta(charset="UTF-8")
meta(name="viewport" content="width=device-width, initial-scale=1.0")
style(type="text/css").
* {
margin: 0;
}
p {
margin: 4px; /* Imposta il margine a 0 per i paragrafi */
}
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f5f5f5;
padding: 20px;
line-height: 1.6;
}
.header-logo {
width: 120px;
height: auto;
margin-bottom: 16px;
display: block;
margin-left: auto;
margin-right: auto;
}
.email-container {
max-width: 600px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.email-header {
background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
color: white;
padding: 40px 24px;
text-align: center;
}
.email-header h1 {
margin: 0 0 8px 0;
font-size: 26px;
font-weight: 600;
line-height: 1.3;
}
.email-header .subtitle {
margin: 8px 0 0 0;
font-size: 17px;
opacity: 0.95;
font-style: italic;
}
.money-icon {
font-size: 56px;
margin-bottom: 12px;
}
.email-body {
padding: 32px 24px;
}
.intro-text {
font-size: 16px;
color: #333;
margin-bottom: 20px;
text-align: center;
line-height: 1.7;
}
.transaction-card {
background: linear-gradient(135deg, #f8fdf8 0%, #e8f5e9 100%);
border: 2px solid #7cb342;
border-radius: 8px;
padding: 24px;
margin: 20px 0;
text-align: center;
}
.transaction-amount {
font-size: 42px;
color: #558b2f;
font-weight: 700;
margin-bottom: 12px;
line-height: 1.2;
}
.transaction-label {
font-size: 14px;
text-transform: uppercase;
color: #558b2f;
font-weight: 600;
letter-spacing: 0.5px;
margin-bottom: 16px;
}
.transaction-detail {
font-size: 15px;
color: #555;
margin: 8px 0;
line-height: 1.5;
}
.transaction-detail strong {
color: #558b2f;
}
.divider-line {
height: 1px;
background: #c8e6c9;
margin: 16px 0;
}
.highlight-box {
background: #fff8dc;
border-left: 4px solid #7cb342;
border-radius: 8px;
padding: 16px;
margin: 20px 0;
}
.highlight-box p {
margin: 0;
font-size: 16px;
color: #1a1a1a;
line-height: 1.6;
}
.highlight-box .label {
font-size: 13px;
text-transform: uppercase;
color: #558b2f;
font-weight: 600;
letter-spacing: 0.5px;
margin-bottom: 6px;
}
.cta-section {
text-align: center;
margin: 24px 0;
padding: 20px 0;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
}
.cta-title {
font-size: 18px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 16px;
}
.cta-button {
display: inline-block;
padding: 16px 48px;
font-size: 18px;
font-weight: 600;
color: white;
background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
border-radius: 50px;
text-decoration: none;
box-shadow: 0 4px 12px rgba(124, 179, 66, 0.3);
transition: all 0.3s ease;
}
.info-box {
background: #e8f5e9;
border-radius: 8px;
padding: 16px;
margin: 20px 0;
text-align: center;
}
.info-box p {
margin: 0;
color: #2e7d32;
font-size: 16px;
line-height: 1.6;
}
.email-footer {
padding: 20px;
text-align: center;
background: #f8f9fa;
color: #777;
font-size: 13px;
}
.email-footer p {
margin: 4px 0;
}
.divider {
height: 1px;
background: linear-gradient(to right, transparent, #e0e0e0, transparent);
margin: 20px 0;
}
@media only screen and (max-width: 600px) {
body {
padding: 10px;
}
.email-header {
padding: 24px 16px;
}
.email-header h1 {
font-size: 22px;
}
.money-icon {
font-size: 48px;
}
.email-body {
padding: 20px 16px;
}
.transaction-amount {
font-size: 36px;
}
.cta-button {
padding: 14px 32px;
font-size: 16px;
width: 100%;
max-width: 300px;
}
}
.grande {
font-size: 1.25rem;
font-weight: bold;
}
body
.email-container
//- Header
.email-header
img.header-logo(src=baseurl+'/images/logo.png' alt='RISO - Rete Italiana Scambio Orizzontale')
h1 Ciao <strong>#{username}</strong>, Hai ricevuto dei #{symbol}!
p.subtitle Nuova transazione sul #{nomecircuito}
//- Body
.email-body
//- Intro
//- Transaction card
.transaction-card
.transaction-label Importo Ricevuto
.transaction-amount +#{qty} #{symbol}
.divider-line
.transaction-detail(style="font-size: 18px; margin-top: 12px;")
strong Nuovo Saldo:
span(style="color: #558b2f; font-weight: 700; font-size: 20px;") #{saldoAttuale} #{symbol}
.transaction-detail
strong Da:
| #{mittente}
.transaction-detail
strong Data:
| #{transactionDate}
if groupDestoContoCom
.transaction-detail
strong Conto:
| #{groupDestoContoCom}
.transaction-detail
strong Circuito:
| #{nomecircuito}
//- Descrizione
if causalDest
.highlight-box
.label 📝 Descrizione
p #{causalDest}
//- Commento mittente
if causale
.highlight-box
.label 💬 Commento di #{mittente}
p "#{causale}"
//- Info box
.info-box
p
| ✓ La transazione è stata registrata con successo<br>
| ✓ Il tuo saldo è stato aggiornato
//- CTA
.cta-section
.cta-title Accedi alla App
a.cta-button(href=strlinksito target="_blank") Apri #{nomeapp}
//- Footer
.email-footer
.divider
p Hai ricevuto questa email perché hai ricevuto una transazione su #{nomeapp}
p(style="margin-top: 12px; font-size: 12px;")
| #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambi Orizzontali
p(style="margin-top: 12px; font-size: 12px;")
| 🍚 Comunità · Fiducia · Scambi Solidali · Sostenibilità

View File

@@ -72,3 +72,9 @@ Gio 20/11 ORE 20:55: USER [surya1977]: ciao
Gio 20/11 ORE 21:15: USER [surya1977]: ciao
Gio 20/11 ORE 21:24: USER [surya5]: ciao
Sab 22/11 ORE 23:30: USER [surya1977]: ciao
Dom 23/11 ORE 00:02: USER [perseo5]: ciao
Dom 23/11 ORE 00:22: USER [perseo7]: ciao

View File

@@ -488,4 +488,30 @@ Ven 03/10 ORE 15:03: [<b>Euro</b>]: Inviate Monete da paoloar77 a piuchebuono 6
Saldi:
paoloar77: -312.80 €]
piuchebuono: 10552.82 €]
piuchebuono: 10552.82 €]
Dom 23/11 ORE 00:52: [<b>Circuito RIS Italia</b>]: Inviate Monete da perseo9 a surya1977 1 RIS [causale: prova 1 Ciaoooooooo]
Saldi:
perseo9: -1.00 RIS]
surya1977: 123.95 RIS]
Dom 23/11 ORE 00:56: [<b>Circuito RIS Italia</b>]: Inviate Monete da perseo9 a surya1977 2 RIS [causale: Eccolo!
]
Saldi:
perseo9: -3.00 RIS]
surya1977: 125.95 RIS]
Dom 23/11 ORE 01:00: [<b>Circuito RIS Italia</b>]: Inviate Monete da perseo9 a surya1977 3 RIS [causale: aaaaa]
Saldi:
perseo9: -6.00 RIS]
surya1977: 128.95 RIS]
Dom 23/11 ORE 01:03: [<b>Circuito RIS Italia</b>]: Inviate Monete da perseo9 a surya1977 4 RIS [causale: BBB]
Saldi:
perseo9: -14.00 RIS]
surya1977: 136.95 RIS]
Dom 23/11 ORE 01:10: [<b>Circuito RIS Italia</b>]: Inviate Monete da perseo9 a surya1977 5 RIS [causale: sdasdas]
Saldi:
perseo9: -19.00 RIS]
surya1977: 141.95 RIS]

View File

@@ -21,14 +21,14 @@ class UserController {
async register(req, res) {
try {
tools.mylog('POST /users - Registration');
// Validate input
const validationError = validateRegistration(req.body);
if (validationError) {
await tools.snooze(5000);
return res.status(400).send({
code: validationError.code,
msg: validationError.message
return res.status(400).send({
code: validationError.code,
msg: validationError.message,
});
}
@@ -38,33 +38,29 @@ class UserController {
// Check security (IP bans, block words, etc.)
const securityCheck = await this._performSecurityChecks(userData, req);
if (securityCheck.blocked) {
return res.status(securityCheck.status).send({
code: securityCheck.code,
msg: securityCheck.message
return res.status(securityCheck.status).send({
code: securityCheck.code,
msg: securityCheck.message,
});
}
// Process registration
const result = await this.registrationService.registerUser(userData, req);
if (result.error) {
return res.status(400).send({
code: result.code,
msg: result.message
return res.status(400).send({
code: result.code,
msg: result.message,
});
}
// Send response with tokens
res
.header('x-auth', result.token)
.header('x-refrtok', result.refreshToken)
.send(result.user);
res.header('x-auth', result.token).header('x-refrtok', result.refreshToken).send(result.user);
} catch (error) {
console.error('Error in registration:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -75,6 +71,7 @@ class UserController {
*/
async login(req, res) {
try {
console.log('LOGIN');
const { username, password, idapp, keyappid } = req.body;
// Validate API key
@@ -85,42 +82,35 @@ class UserController {
// Validate input
const validationError = validateLogin(req.body);
if (validationError) {
return res.status(400).send({
code: validationError.code,
msg: validationError.message
return res.status(400).send({
code: validationError.code,
msg: validationError.message,
});
}
// Attempt login
const result = await this.authService.authenticate(
idapp,
username,
password,
req
);
const result = await this.authService.authenticate(idapp, username, password, req);
console.log('attempt...', result);
if (result.error) {
return res.status(result.status).send({
code: result.code,
msg: result.message
return res.status(result.status).send({
code: result.code,
msg: result.message,
});
}
// Send response with tokens
res
.header('x-auth', result.token)
.header('x-refrtok', result.refreshToken)
.send({
usertosend: result.user,
code: server_constants.RIS_CODE_OK,
subsExistonDb: result.subsExistonDb
});
res.header('x-auth', result.token).header('x-refrtok', result.refreshToken).send({
usertosend: result.user,
code: server_constants.RIS_CODE_OK,
subsExistonDb: result.subsExistonDb,
});
} catch (error) {
console.error('Error in login:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_LOGIN_ERR_GENERIC,
msgerr: error.message
res.status(400).send({
code: server_constants.RIS_CODE_LOGIN_ERR_GENERIC,
msgerr: error.message,
});
}
}
@@ -141,20 +131,14 @@ class UserController {
}
// Get user profile
const profile = await this.userService.getUserProfile(
idapp,
username,
usernameOrig,
perm
);
const profile = await this.userService.getUserProfile(idapp, username, usernameOrig, perm);
res.send(profile);
} catch (error) {
console.error('Error in getProfile:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -168,21 +152,14 @@ class UserController {
const username = req.user.username;
const { idapp, circuitId, groupname, lastdr } = req.body;
const result = await this.userService.updateUserBalance(
idapp,
username,
circuitId,
groupname,
lastdr
);
const result = await this.userService.updateUserBalance(idapp, username, circuitId, groupname, lastdr);
res.send({ ris: result });
} catch (error) {
console.error('Error in updateSaldo:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -197,14 +174,13 @@ class UserController {
const { idapp } = req.body;
const friends = await this.userService.getUserFriends(idapp, username);
res.send(friends);
res.send(friends);
} catch (error) {
console.error('Error in getFriends:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -220,28 +196,20 @@ class UserController {
// Security check
if (!this._canExecuteFriendCommand(req.user, usernameOrig, usernameDest, cmd)) {
return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
msg: ''
return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
msg: '',
});
}
const result = await this.userService.executeFriendCommand(
req,
idapp,
usernameOrig,
usernameDest,
cmd,
value
);
const result = await this.userService.executeFriendCommand(req, idapp, usernameOrig, usernameDest, cmd, value);
res.send(result);
} catch (error) {
console.error('Error in executeFriendCommand:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -256,14 +224,13 @@ class UserController {
const { idapp } = req.body;
const groups = await this.userService.getUserGroups(idapp, username, req);
res.send(groups);
res.send(groups);
} catch (error) {
console.error('Error in getGroups:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -277,20 +244,14 @@ class UserController {
const username = req.user.username;
const { idapp, nummovTodownload } = req.body;
const circuits = await this.userService.getUserCircuits(
idapp,
username,
req.user,
nummovTodownload
);
res.send(circuits);
const circuits = await this.userService.getUserCircuits(idapp, username, req.user, nummovTodownload);
res.send(circuits);
} catch (error) {
console.error('Error in getCircuits:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -315,9 +276,8 @@ class UserController {
res.status(200).send({
token: result.token,
refreshToken: result.refreshToken
refreshToken: result.refreshToken,
});
} catch (error) {
console.error('Error in refreshToken:', error.message);
res.status(500).send({ error: 'Errore interno del server' });
@@ -353,7 +313,6 @@ class UserController {
}
res.status(200).send();
} catch (error) {
console.error('Error in checkUsername:', error.message);
res.status(400).send();
@@ -371,11 +330,10 @@ class UserController {
await this.userService.setUserPermissions(req.user._id, {
idapp,
username,
perm
perm,
});
res.status(200).send();
} catch (error) {
console.error('Error in setPermissions:', error.message);
res.status(400).send();
@@ -392,28 +350,22 @@ class UserController {
// Check permissions
if (!this._hasAdminPermissions(req.user)) {
return res.status(404).send({
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED
return res.status(404).send({
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
});
}
const result = await this.userService.executeDbOperation(
idapp,
mydata,
req,
res
);
const result = await this.userService.executeDbOperation(idapp, mydata, req, res);
res.send({
code: server_constants.RIS_CODE_OK,
data: result
res.send({
code: server_constants.RIS_CODE_OK,
data: result,
});
} catch (error) {
console.error('Error in executeDbOperation:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -428,16 +380,15 @@ class UserController {
const mapData = await this.userService.getMapInformation(idapp);
res.send({
code: server_constants.RIS_CODE_OK,
ris: mapData
res.send({
code: server_constants.RIS_CODE_OK,
ris: mapData,
});
} catch (error) {
console.error('Error in getMapInfo:', error.message);
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message
res.status(400).send({
code: server_constants.RIS_CODE_ERR,
msg: error.message,
});
}
}
@@ -446,13 +397,21 @@ class UserController {
_extractUserData(body) {
const fields = [
'email', 'password', 'username', 'group', 'name',
'surname', 'idapp', 'keyappid', 'lang', 'profile',
'aportador_solidario'
'email',
'password',
'username',
'group',
'name',
'surname',
'idapp',
'keyappid',
'lang',
'profile',
'aportador_solidario',
];
const userData = {};
fields.forEach(field => {
fields.forEach((field) => {
if (body[field] !== undefined) {
userData[field] = body[field];
}
@@ -469,16 +428,14 @@ class UserController {
async _performSecurityChecks(userData, req) {
const { User } = require('../models/user');
// Check for blocked words
if (tools.blockwords(userData.username) ||
tools.blockwords(userData.name) ||
tools.blockwords(userData.surname)) {
if (tools.blockwords(userData.username) || tools.blockwords(userData.name) || tools.blockwords(userData.surname)) {
await tools.snooze(5000);
return {
blocked: true,
status: 404,
code: server_constants.RIS_CODE_ERR
return {
blocked: true,
status: 404,
code: server_constants.RIS_CODE_ERR,
};
}
@@ -492,11 +449,11 @@ class UserController {
tools.writeIPToBan(msg);
await telegrambot.sendMsgTelegramToTheAdmin(userData.idapp, '‼️ BAN: ' + msg, true);
await tools.snooze(5000);
return {
blocked: true,
status: 400,
code: server_constants.RIS_CODE_BANIP
return {
blocked: true,
status: 400,
code: server_constants.RIS_CODE_BANIP,
};
}
}
@@ -507,15 +464,12 @@ class UserController {
_canExecuteFriendCommand(user, usernameOrig, usernameDest, cmd) {
const { User } = require('../models/user');
if (User.isAdmin(user.perm) || User.isManager(user.perm)) {
return true;
}
const allowedCommands = [
shared_consts.FRIENDSCMD.SETFRIEND,
shared_consts.FRIENDSCMD.SETHANDSHAKE
];
const allowedCommands = [shared_consts.FRIENDSCMD.SETFRIEND, shared_consts.FRIENDSCMD.SETHANDSHAKE];
if (allowedCommands.includes(cmd)) {
return usernameOrig === user.username || usernameDest === user.username;
@@ -530,4 +484,4 @@ class UserController {
}
}
module.exports = UserController;
module.exports = UserController;

View File

@@ -90,7 +90,7 @@ exports.checkVerification = async (req, res) => {
// Controlla se è stato verificato
const verified = !!(user.profile?.teleg_id && user.profile?.username_telegram);
res.json({
return res.json({
verified: verified,
username_telegram: user.profile?.username_telegram || null,
teleg_id: user.profile?.teleg_id || null,

View File

@@ -37,21 +37,23 @@ function clearFailedAttempts(username) {
*/
function checkBlocked(req, res, next) {
const { username } = req.body;
console.log('checkBlocked');
if (!username) {
return res.status(400).json({
message: 'Username mancante'
return res.status(400).json({
message: 'Username mancante',
});
}
if (isUserBlocked(username)) {
const text = `Utente bloccato. Riprova più tardi. (username=${username})`;
console.log(text);
return res.status(403).json({
message: 'Utente bloccato. Riprova più tardi.'
return res.status(403).json({
message: 'Utente bloccato. Riprova più tardi.',
});
}
next();
}
@@ -92,30 +94,30 @@ function rateLimitByIP(req, res, next) {
const tools = require('../tools/general');
const ip = tools.getiPAddressUser(req);
const now = Date.now();
if (!requestCounts[ip]) {
requestCounts[ip] = {
count: 1,
resetTime: now + REQUEST_WINDOW
resetTime: now + REQUEST_WINDOW,
};
return next();
}
if (now > requestCounts[ip].resetTime) {
// Reset window
requestCounts[ip] = {
count: 1,
resetTime: now + REQUEST_WINDOW
resetTime: now + REQUEST_WINDOW,
};
return next();
}
if (requestCounts[ip].count >= MAX_REQUESTS) {
return res.status(429).json({
message: 'Troppi tentativi. Riprova più tardi.'
return res.status(429).json({
message: 'Troppi tentativi. Riprova più tardi.',
});
}
requestCounts[ip].count++;
next();
}
@@ -125,9 +127,8 @@ function rateLimitByIP(req, res, next) {
*/
function cleanupBlockedUsers() {
const now = Date.now();
Object.keys(failedLoginAttempts).forEach(username => {
if (typeof failedLoginAttempts[username] === 'number' &&
failedLoginAttempts[username] < now) {
Object.keys(failedLoginAttempts).forEach((username) => {
if (typeof failedLoginAttempts[username] === 'number' && failedLoginAttempts[username] < now) {
delete failedLoginAttempts[username];
}
});
@@ -146,5 +147,5 @@ module.exports = {
shouldBlockUser,
rateLimitByIP,
MAX_FAILED_ATTEMPTS,
BLOCK_DURATION
};
BLOCK_DURATION,
};

View File

@@ -899,7 +899,7 @@ CircuitSchema.statics.sendCoins = async function (onlycheck, idapp, usernameOrig
let myuserDest = await User.getUserByUsername(idapp, extrarec.dest);
// Invia una email al destinatario !
await sendemail.sendEmail_RisRicevuti(myuserDest.lang, myuserDest, myuserDest.email, idapp, paramsrec);
await sendemail.sendEmail_RisRicevuti(myuserDest.lang, myuserDest, myuserDest.email, idapp, paramsrec, extrarec);
} else if (extrarec.groupdest || extrarec.contoComDest) {
const groupDestoContoCom = extrarec.groupdest
? extrarec.groupdest
@@ -1142,7 +1142,8 @@ CircuitSchema.statics.getCircuitMyProvince = async function (idapp, username) {
CircuitSchema.statics.createCircuitIfNotExist = async function (req, idapp, province, card) {
const { User } = require('../models/user');
const useradmin = shared_consts.USER_ADMIN_CIRCUITS;
const admins = shared_consts.USER_ADMIN_CIRCUITS;
const useradmin = shared_consts.USER_ADMIN_SINGOLO;
let myrec = null;
try {
@@ -1174,7 +1175,7 @@ CircuitSchema.statics.createCircuitIfNotExist = async function (req, idapp, prov
totTransato: 0,
totCircolante: 0,
date_created: new Date(),
admins: useradmin.map((username) => ({ username })),
admins: admins.map((username) => ({ username })),
askManagerToEnter: false,
sendEmailAfterAskingToEnter: false,
circuitoIndipendente: false,

File diff suppressed because it is too large Load Diff

375
src/router/users_router_new.js Executable file
View File

@@ -0,0 +1,375 @@
const express = require('express');
const router = express.Router();
const UserController = require('../controllers/UserController');
const { authenticate, authenticate_noerror, authenticate_withUser } = require('../middleware/authenticate');
const { checkBlocked } = require('../middleware/securityMiddleware');
// Initialize controller
const userController = new UserController();
// ===== PUBLIC ROUTES =====
/**
* Register new user
* POST /users
*/
router.post('/', (req, res) => userController.register(req, res));
/**
* Check if username exists
* GET /users/:idapp/:username
*/
router.get('/:idapp/:username', (req, res) => userController.checkUsername(req, res));
/**
* User login
* POST /users/login
*/
router.post('/login', checkBlocked, (req, res) => userController.login(req, res));
/**
* Refresh authentication token
* POST /users/newtok
*/
router.post('/newtok', (req, res) => userController.refreshToken(req, res));
/**
* Get user activities (public profile)
* POST /users/activities
*/
router.post('/activities', authenticate_noerror, (req, res) =>
userController.getProfile(req, res)
);
// ===== AUTHENTICATED ROUTES =====
/**
* Get user profile
* POST /users/profile
*/
router.post('/profile', authenticate, (req, res) =>
userController.getProfile(req, res)
);
/**
* Get user panel info (admin/manager only)
* POST /users/panel
*/
router.post('/panel', authenticate, (req, res) => {
const { User } = require('../models/user');
const server_constants = require('../tools/server_constants');
if (!req.user || (!User.isAdmin(req.user.perm) &&
!User.isManager(req.user.perm) &&
!User.isFacilitatore(req.user.perm))) {
return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
msg: ''
});
}
userController.getProfile(req, res);
});
/**
* Update user balance
* POST /users/updatesaldo
*/
router.post('/updatesaldo', authenticate, (req, res) =>
userController.updateSaldo(req, res)
);
/**
* Get user's friends
* POST /users/friends
*/
router.post('/friends', authenticate, (req, res) =>
userController.getFriends(req, res)
);
/**
* Execute friend command
* POST /users/friends/cmd
*/
router.post('/friends/cmd', authenticate, (req, res) =>
userController.executeFriendCommand(req, res)
);
/**
* Send command to user
* POST /users/sendcmd
*/
router.post('/sendcmd', authenticate, (req, res) => {
const usernameLogged = req.user.username;
const { idapp, usernameOrig, usernameDest, cmd, value } = req.body;
userController.userService.sendCommand(
req, idapp, usernameOrig, usernameDest, cmd, value
).then(result => res.send(result))
.catch(error => res.status(400).send({ error: error.message }));
});
/**
* Get user's groups
* POST /users/groups
*/
router.post('/groups', authenticate, (req, res) =>
userController.getGroups(req, res)
);
/**
* Execute group command
* POST /users/groups/cmd
*/
router.post('/groups/cmd', authenticate, (req, res) => {
const usernameLogged = req.user.username;
const { idapp, usernameOrig, groupnameDest, cmd, value } = req.body;
userController.userService.executeGroupCommand(
idapp, usernameOrig, groupnameDest, cmd, value, usernameLogged
).then(result => res.send(result))
.catch(error => res.status(400).send({ error: error.message }));
});
/**
* Get user's circuits
* POST /users/circuits
*/
router.post('/circuits', authenticate_withUser, (req, res) =>
userController.getCircuits(req, res)
);
/**
* Execute circuit command
* POST /users/circuits/cmd
*/
router.post('/circuits/cmd', authenticate, async (req, res) => {
const usernameLogged = req.user.username;
const { idapp, usernameOrig, circuitname, cmd, value, extrarec } = req.body;
try {
const result = await userController.userService.executeCircuitCommand(
idapp, usernameOrig, circuitname, cmd, value, usernameLogged, extrarec
);
res.send(result);
} catch (error) {
res.status(400).send({ error: error.message });
}
});
/**
* Logout user
* DELETE /users/me/token
*/
router.delete('/me/token', authenticate_withUser, (req, res) =>
userController.logout(req, res)
);
/**
* Set user permissions
* POST /users/setperm
*/
router.post('/setperm', authenticate, (req, res) =>
userController.setPermissions(req, res)
);
/**
* Get last movements/transactions
* POST /users/lastmovs
*/
router.post('/lastmovs', authenticate, async (req, res) => {
const { nummov, nummov_uscita, idapp } = req.body;
const server_constants = require('../tools/server_constants');
const tools = require('../tools/general');
try {
const { Movement } = require('../models/movement');
let last_transactions = [];
if (nummov) {
last_transactions = await Movement.getLastN_Transactions(idapp, nummov, nummov_uscita);
}
res.send({ code: server_constants.RIS_CODE_OK, last_transactions });
} catch (e) {
tools.mylogserr('Error lastmovs: ', e);
res.status(400).send();
}
});
/**
* Set receive RIS flag
* POST /users/receiveris
*/
router.post('/receiveris', authenticate, async (req, res) => {
const username = req.user?.username || '';
const { groupname, idapp } = req.body;
const { User } = require('../models/user');
const { MyGroup } = require('../models/mygroup');
const server_constants = require('../tools/server_constants');
const tools = require('../tools/general');
try {
if (!username) {
return res.send({ code: server_constants.RIS_CODE_ERR });
}
if (groupname) {
await MyGroup.setReceiveRisGroup(idapp, groupname);
} else {
await User.setReceiveRis(idapp, username);
}
res.send({ code: server_constants.RIS_CODE_OK });
} catch (err) {
tools.mylog('ERRORE IN receiveris: ' + err.message);
res.status(400).send();
}
});
/**
* List registration links
* POST /users/listlinkreg
*/
router.post('/listlinkreg', authenticate, async (req, res) => {
const username = req.user?.username || '';
const { idapp } = req.body;
const { User } = require('../models/user');
const server_constants = require('../tools/server_constants');
const tools = require('../tools/general');
try {
if (!username) {
return res.send({ code: server_constants.RIS_CODE_ERR });
}
await User.setLinkReg(idapp, username);
res.send({ code: server_constants.RIS_CODE_OK });
} catch (err) {
tools.mylog('ERRORE IN listlinkreg: ' + err.message);
res.status(400).send();
}
});
// ===== ADMIN ROUTES =====
/**
* Update user (admin only)
* PATCH /users/:id
*/
router.patch('/:id', authenticate, (req, res) => {
const { User } = require('../models/user');
const _ = require('lodash');
const shared_consts = require('../tools/shared_nodejs');
const server_constants = require('../tools/server_constants');
const tools = require('../tools/general');
const id = req.params.id;
const body = _.pick(req.body.user, shared_consts.fieldsUserToChange());
tools.mylogshow('PATCH USER: ', id);
if (!User.isAdmin(req.user.perm)) {
return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
msg: ''
});
}
User.findByIdAndUpdate(id, { $set: body })
.then((user) => {
tools.mylogshow(' USER TO MODIFY: ', user);
if (!user) {
return res.status(404).send();
}
res.send({ code: server_constants.RIS_CODE_OK, msg: '' });
})
.catch((e) => {
tools.mylogserr('Error patch USER: ', e);
res.status(400).send();
});
});
/**
* Execute database operation (admin only)
* POST /users/dbop
*/
router.post('/dbop', authenticate, (req, res) =>
userController.executeDbOperation(req, res)
);
/**
* Execute user database operation
* POST /users/dbopuser
*/
router.post('/dbopuser', authenticate, async (req, res) => {
const { mydata, idapp } = req.body;
const server_constants = require('../tools/server_constants');
try {
const result = await userController.userService.executeUserDbOperation(
idapp,
mydata,
req.user.username
);
res.send({ code: server_constants.RIS_CODE_OK, ris: result });
} catch (e) {
res.status(400).send({ code: server_constants.RIS_CODE_ERR, msg: e.message });
}
});
/**
* Get map information
* POST /users/infomap
*/
router.post('/infomap', authenticate, (req, res) =>
userController.getMapInfo(req, res)
);
/**
* Management telegram operations
* POST /users/mgt
*/
router.post('/mgt', authenticate_withUser, async (req, res) => {
const { mydata, idapp } = req.body;
const telegrambot = require('../telegram/telegrambot');
try {
const { nummsgsent, numrec, textsent, text } =
await telegrambot.sendMsgFromSiteToBotTelegram(idapp, req.user, mydata);
res.send({ numrec, nummsgsent, textsent, text });
} catch (e) {
res.status(400).send({ error: e.message });
}
});
// ===== TEST ROUTES (Development only) =====
if (process.env.NODE_ENV === 'development' || process.env.LOCALE === '1') {
router.post('/test1', async (req, res) => {
const { User } = require('../models/user');
const sendemail = require('../sendemail');
const user = await User.findOne({
idapp: 1,
username: 'paoloar77'
});
if (user) {
await sendemail.sendEmail_Registration(
user.lang,
user.email,
user,
user.idapp,
user.linkreg
);
}
res.send({ success: true });
});
}
module.exports = router;

View File

@@ -500,10 +500,12 @@ module.exports = {
},
getPathEmail(idapp, email_template) {
const RISO_TEMPLATES = ['reg_notifica_all_invitante'];
const RISO_TEMPLATES = ['reg_notifica_all_invitante', 'reg_email_benvenuto_ammesso'];
if (RISO_TEMPLATES.includes(email_template)) {
return tools.RISO_STR_PATH + '/' + email_template;
if (idapp === '13') {
if (RISO_TEMPLATES.includes(email_template)) {
return tools.RISO_STR_PATH + '/' + email_template;
}
}
return 'defaultSite/' + email_template;
},
@@ -525,6 +527,8 @@ module.exports = {
usernameInvitante: user.aportador_solidario,
nomeInvitante: nomecognomeInvitante.trim(),
nomeInvitato: await User.getNameSurnameEUsernameByUsername(idapp, user.username),
usernameInvitato: user.username,
emailInvitato: user.email,
user,
};
@@ -534,7 +538,7 @@ module.exports = {
if (user.verified_email) {
// se l'utente è già stato verificata la sua email, allora gli mando direttamente la email di invito.
quale_email_inviare = 'reg_email_benvenuto_ammesso/' + lang;
quale_email_inviare = this.getPathEmail(idapp, 'reg_email_benvenuto_ammesso') + '/' + lang;
} else {
// altrimenti gli mando l'email con la richiesta di Verifica email
quale_email_inviare = tools.getpathregByIdApp(idapp, lang);
@@ -583,7 +587,7 @@ module.exports = {
sendEmail_InvitaAmico: async function (lang, emailto, user, idapp, dati) {
try {
const nomecognomeInvitante = await User.getNameSurnameByUsername(idapp, dati.usernameInvitante, true);
let mylocalsconf = {
idapp,
dataemail: await this.getdataemail(idapp),
@@ -621,6 +625,7 @@ module.exports = {
linkRegistrazione: this.getlinkInvitoReg(idapp, dati),
emailto: emailto,
usernameInvitante: dati.usernameInvitante,
ammessoUtente: true,
};
const ris = await this.sendEmail_base('reg_email_benvenuto_ammesso/' + lang, emailto, mylocalsconf, '');
@@ -705,17 +710,19 @@ module.exports = {
await this.sendEmail_base('resetpwd/' + lang, emailto, mylocalsconf, '');
},
sendEmail_RisRicevuti: async function (lang, userDest, emailto, idapp, myrec) {
sendEmail_RisRicevuti: async function (lang, userDest, emailto, idapp, myrec, extrarec) {
console.log('sendEmail_RisRicevuti');
let mylocalsconf = {
idapp,
baseurl: tools.getHostByIdApp(idapp),
dataemail: await this.getdataemail(idapp),
locale: lang,
nomeapp: tools.getNomeAppByIdApp(idapp),
strlinksito: tools.getHostByIdApp(idapp),
emailto: emailto,
qty: myrec.qty,
saldoAttuale: extrarec.saldoDest,
mittente: decode(myrec.mittente),
nomecircuito: decode(myrec.nomecircuito),
transactionDate: tools.getstrDate_DD_MM_YYYY(myrec.transactionDate),

View File

@@ -16,6 +16,7 @@ class AuthService {
*/
async authenticate(idapp, username, password, req) {
try {
console.log('STO FACENDO LOGIN...');
// Check if user is blocked
if (this.isUserBlocked(username)) {
const text = `Utente bloccato. Riprova più tardi. (username=${username})`;
@@ -24,13 +25,15 @@ class AuthService {
error: true,
status: 403,
code: server_constants.RIS_CODE_ERR,
message: text
message: text,
};
}
// Find user by credentials
const user = await User.findByCredentials(idapp, username, password);
console.log('user', user);
if (!user) {
return await this._handleFailedLogin(idapp, username, req);
}
@@ -44,27 +47,25 @@ class AuthService {
// Prepare user data to send
const userToSend = this._prepareUserData(user);
console.log('userToSend', userToSend);
// Check subscription
const subsExistonDb = await this._checkSubscription(
user._id,
req.get('User-Agent')
);
const subsExistonDb = await this._checkSubscription(user._id, req.get('User-Agent'));
return {
error: false,
token,
refreshToken,
user: userToSend,
subsExistonDb
subsExistonDb,
};
} catch (error) {
console.error('Error in authenticate:', error.message);
return {
error: true,
status: 400,
code: server_constants.RIS_CODE_LOGIN_ERR_GENERIC,
message: error.message
message: error.message,
};
}
}
@@ -78,7 +79,7 @@ class AuthService {
return {
error: true,
status: 400,
message: 'Refresh token mancante'
message: 'Refresh token mancante',
};
}
@@ -88,7 +89,7 @@ class AuthService {
return {
error: true,
status: 403,
message: 'Refresh token non valido'
message: 'Refresh token non valido',
};
}
@@ -97,15 +98,14 @@ class AuthService {
return {
error: false,
token,
refreshToken: newRefreshToken
refreshToken: newRefreshToken,
};
} catch (error) {
console.error('Error in refreshToken:', error.message);
return {
error: true,
status: 500,
message: 'Errore interno del server'
message: 'Errore interno del server',
};
}
}
@@ -128,8 +128,7 @@ class AuthService {
*/
isUserBlocked(username) {
const now = Date.now();
return this.failedLoginAttempts[username] &&
this.failedLoginAttempts[username] > now;
return this.failedLoginAttempts[username] && this.failedLoginAttempts[username] > now;
}
/**
@@ -148,15 +147,17 @@ class AuthService {
const loginCheck = await User.tooManyLoginWrong(idapp, username, true);
if (loginCheck.troppilogin) {
const text = `Troppe richieste di Login ERRATE: ${username} [IP: ${tools.getiPAddressUser(req)}] Tentativi: ${loginCheck.retry_pwd}`;
const text = `Troppe richieste di Login ERRATE: ${username} [IP: ${tools.getiPAddressUser(req)}] Tentativi: ${
loginCheck.retry_pwd
}`;
await telegrambot.sendMsgTelegramToTheManagers(idapp, text);
console.log('/login', text);
return {
error: true,
status: 400,
code: server_constants.RIS_CODE_ERR,
message: text
message: text,
};
}
@@ -182,15 +183,17 @@ class AuthService {
// Block user after max attempts
if (this.failedLoginAttempts[username] >= this.MAX_FAILED_ATTEMPTS) {
this.blockUser(username);
const text = `Troppi tentativi di accesso falliti. Utente bloccato (${username}) [IP: ${tools.getiPAddressUser(req)}]`;
const text = `Troppi tentativi di accesso falliti. Utente bloccato (${username}) [IP: ${tools.getiPAddressUser(
req
)}]`;
tools.mylogshow(text);
await telegrambot.sendMsgTelegramToTheManagers(idapp, text);
return {
error: true,
status: 403,
code: server_constants.RIS_CODE_ERR,
message: text
message: text,
};
}
@@ -198,7 +201,7 @@ class AuthService {
error: true,
status: 401,
code: server_constants.RIS_CODE_LOGIN_ERR,
message: 'Credenziali non valide'
message: 'Credenziali non valide',
};
}
@@ -210,7 +213,7 @@ class AuthService {
const shared_consts = require('../tools/shared_nodejs');
const userToSend = new User();
shared_consts.fieldsUserToChange().forEach(field => {
shared_consts.fieldsUserToChange().forEach((field) => {
userToSend[field] = user[field];
});
@@ -226,7 +229,7 @@ class AuthService {
const subscription = await Subscription.findOne({
userId,
access: 'auth',
browser: userAgent
browser: userAgent,
}).lean();
return !!subscription;
@@ -237,4 +240,4 @@ class AuthService {
}
}
module.exports = AuthService;
module.exports = AuthService;

View File

@@ -447,6 +447,7 @@ const txt = {
MSG_APORTADOR_USER_REGISTERED: emo.FIRE + ' Si è appena Registrato "%s" (n. %s)\nInvitato da %s',
MSG_APORTADOR_ASK_CONFIRM:
'🆕💥 🧍‍♂️ %s si sta registrando su %s e ti chiede di poter entrare. Confermi di conoscerla ?',
MSG_APORTADOR_INVITED_REGISTERED: '🆕💥 🧍‍♂️ Complimenti! Il tuo invitato %s si è appena registrato su %s !',
MSG_ACCEPT_NEWENTRY_INGROUP: '❇️👥 🧍‍♂️ Accetta Ingresso nel GRUPPO %s:',
MSG_FRIENDS_NOT_ACCEPTED_CONFIRMED: '🚫 Hai rifiutato la richiesta di Amicizia di %s !',
MSG_HANDSHAKE_NOT_ACCEPTED_CONFIRMED: '🚫 Hai rifiutato la richiesta di Stretta di mano di %s !',
@@ -795,7 +796,6 @@ const MyTelegramBot = {
text = printf(getstr(langdest, 'MSG_APORTADOR_USER_REGISTERED'), nome, numutenti, aportador);
}
} else if (phase === this.phase.INVITA_AMICO) {
}
let addtext = '';
@@ -903,25 +903,31 @@ const MyTelegramBot = {
// Non chiedi la verifica Registrazione
await setVerifiedReg(myuser.idapp, myuser.lang, myuser.username, userDest);
} else {
msg_notifpush = getstr(langdest, 'MSG_APORTADOR_ASK_CONFIRM', myuser.username, nomeapp);
domanda = getstr(langdest, 'MSG_APORTADOR_ASK_CONFIRM', myuser.username, nomeapp) + '<br>' + struserinfomsg;
keyb = cl.getInlineKeyboard(myuser.lang, [
{
text: '✅ Ammetti ' + myuser.username,
callback_data: InlineConferma.RISPOSTA_SI + myfunc + tools.SEP + myuser.username + tools.SEP + userDest,
},
/*{
if (myuser.verified_by_aportador) {
msg_notifpush = getstr(langdest, 'MSG_APORTADOR_INVITED_REGISTERED', myuser.username, nomeapp);
domanda =
getstr(langdest, 'MSG_APORTADOR_INVITED_REGISTERED', myuser.username, nomeapp) + '<br>' + struserinfomsg;
} else {
msg_notifpush = getstr(langdest, 'MSG_APORTADOR_ASK_CONFIRM', myuser.username, nomeapp);
domanda = getstr(langdest, 'MSG_APORTADOR_ASK_CONFIRM', myuser.username, nomeapp) + '<br>' + struserinfomsg;
keyb = cl.getInlineKeyboard(myuser.lang, [
{
text: '✅ Ammetti ' + myuser.username,
callback_data: InlineConferma.RISPOSTA_SI + myfunc + tools.SEP + myuser.username + tools.SEP + userDest,
},
]);
}
/*{
text: '🚫 Rifiuta ' + myuser.username,
callback_data: InlineConferma.RISPOSTA_NO + myfunc + tools.SEP + myuser.username + tools.SEP + userDest,
}, */
]);
}
send_notif = true;
} else if (myfunc === shared_consts.CallFunz.VERIFICA_TELEGRAM) {
if (telegid > 0) {
cl.setPhotoProfile(myuser, telegid, false);
const rismsg = await MsgTemplate.getMsgByLang(
idapp,
myuser,
@@ -930,6 +936,23 @@ const MyTelegramBot = {
);
await cl.sendMsgLog(telegid, rismsg.body);
// Invia notifica Teelgram all'Invitante che il suo invitato si è Verificato con Telegram.
userDest = myuser.aportador_solidario;
let useraportador = await User.getUserShortDataByUsername(idapp, userDest);
const rismsg2 = await MsgTemplate.getMsgByLang(
idapp,
myuser,
shared_consts.TypeMsgTemplate.MSG_VERIFICA_TELEGRAM_COMPLETATA_NOTIF_INVITANTE,
myuser.lang
);
const telegidInvitante = useraportador.profile.teleg_id;
await cl.sendMsgLog(telegidInvitante, rismsg2.body);
}
} else if (myfunc === shared_consts.CallFunz.RICHIESTA_GRUPPO) {
msg_notifpush = printf(getstr(langdest, 'MSG_ACCEPT_NEWENTRY_INGROUP'), name);
@@ -1091,6 +1114,7 @@ const MyTelegramBot = {
}
},
askConfirmationUserFriend: async function (idapp, myfunc, myuser, userDest = '', username = '') {
try {
const cl = getclTelegByidapp(idapp);
@@ -1255,22 +1279,7 @@ const MyTelegramBot = {
let title = '';
let msg = '';
if (mydata.tipomsg === tools.TipoMsg.SEND_LINK_CHAT_DONATORI) {
if (sonosognatore)
msg = printf(
tools.gettranslate('SEND_LINK_CHAT_SOGNATORE', lang),
user.name,
mydata.navemediatore.riga + '.' + mydata.navemediatore.col,
mydata.msgpar1
);
else
msg = printf(
tools.gettranslate('SEND_LINK_CHAT_DONATORI', lang),
user.name,
mydata.navemediatore.riga + '.' + mydata.navemediatore.col,
mydata.msgpar1
);
} else if (mydata.tipomsg === tools.TipoMsg.SEND_MSG || mydata.tipomsg === tools.TipoMsg.SEND_MSG_SINGOLO) {
if (mydata.tipomsg === tools.TipoMsg.SEND_MSG || mydata.tipomsg === tools.TipoMsg.SEND_MSG_SINGOLO) {
if (!!mydata.username_mitt) {
msg = '[' + tools.gettranslate('MSG_SEND_FROM', lang) + ' ' + mydata.username_mitt + ']:' + tools.ACAPO;
}
@@ -1285,32 +1294,6 @@ const MyTelegramBot = {
if (cl) {
msg = await tools.convertSpecialTags(rec.user, msg);
}
if (!!mydata.flotta) {
// SOSTITUISCI LE PAROLE CHIAVI
if (!!mydata.flotta.date_start)
msg = msg.replace('{date_start}', tools.getstrDateLongTot(new Date(mydata.flotta.date_start), user.lang));
if (!!mydata.flotta.date_close)
msg = msg.replace('{date_close}', tools.getstrDateLongTot(new Date(mydata.flotta.date_close), user.lang));
if (!!mydata.flotta.link_superchat) msg = msg.replace('{link_superchat}', mydata.flotta.link_superchat);
if (!!mydata.flotta.tutor1) msg = msg.replace('{tutor1}', mydata.flotta.tutor1);
if (!!mydata.flotta.tutor2) msg = msg.replace('{tutor2}', mydata.flotta.tutor2);
if (!!mydata.flotta.tutor3) msg = msg.replace('{tutor3}', mydata.flotta.tutor3);
if (!!mydata.flotta.tutorslo) msg = msg.replace('{tutorslo}', mydata.flotta.tutorslo);
if (!!mydata.flotta.sognatore_nomecognome) msg = msg.replace('{sognatore}', mydata.flotta.sognatore_nomecognome);
if (!!mydata.flotta.sognatore_nomecognome)
msg = msg.replace(
'{flotta}',
mydata.flotta.riga +
'.' +
Math.ceil(mydata.flotta.col_prima / 8) +
' - ' +
mydata.flotta.riga +
'.' +
Math.ceil(mydata.flotta.col_ultima / 8)
);
}
return { body: msg, title };
},
@@ -1926,7 +1909,7 @@ class Telegram {
risp = 'Siiiii ! Davvero! ' + emo.DREAM;
} else if (MsgBot.PAROLACCE.find((rec) => testo.indexOf(rec) > -1)) {
risp = "Da te non me l'aspettavo proprio !! " + emo.INNOCENT + emo.CROSS_ROSSA;
// } else if (MsgBot.OK.find((rec) => testo.indexOf(rec) > -1)) {
// } else if (MsgBot.OK.find((rec) => testo.indexOf(rec) > -1)) {
// risp = '👍🏻';
} else if (MsgBot.CUORE.find((rec) => testo.indexOf(rec) > -1)) {
risp = '❤️💚💜';
@@ -3332,27 +3315,27 @@ class Telegram {
if (!msg.from.username) {
rec.cmdAfterVerified === shared_consts.CallFunz.VERIFICA_TELEGRAM;
} else {
await this.verificaTelegramCompleted(msg);
await this.verificaTelegramCompleted(msg, recuser);
}
}
}
}
async verificaTelegramCompleted(msg) {
async verificaTelegramCompleted(msg, recuser) {
try {
const rec = this.getRecInMem(msg);
const id = msg.chat.id;
const recuser = this.getRecInMemById(id);
if (recuser) {
if (rec && recuser) {
await User.setUsernameTelegram(
this.idapp,
recuser.user._id,
recuser._id,
msg.from.username || '',
msg.from.first_name || '',
msg.from.last_name || ''
);
rec.status = Status.VERIFIED;
rec.datemenu_updated = null;
rec.menuDb = null;
@@ -4595,7 +4578,6 @@ if (true) {
);
// Invia una email alla persona che è stata ammessa
await local_sendMsgTelegram(user.idapp, data.username, msgOrig);
await local_sendMsgTelegram(user.idapp, data.userDest, msgDest);

View File

@@ -2145,7 +2145,6 @@ module.exports = {
}
},
getTelegramKeyByIdApp: function (idapp) {
if (this.MYAPPS.length === 0) {
console.error('❌ this.MYAPPS VUOTI!!', this.MYAPPS);
@@ -3942,7 +3941,7 @@ module.exports = {
try {
return await this.readfilecontent(__dirname + '/../version.txt');
} catch (e) {
return ''
return '';
}
},
@@ -4450,12 +4449,34 @@ module.exports = {
},
getNomeCognomeEUserNameByUser(user) {
let nome = `${user.name} ${user.surname} (${user.username})`;
if (!user.name) {
nome = user.username;
if (!user) return '';
const name = user.name?.trim() || '';
const surname = user.surname?.trim() || '';
const username = user.username?.trim() || '';
// Se ci sono nome e cognome
if (name && surname) {
return username ? `${name} ${surname} (${username})` : `${name} ${surname}`;
}
return nome;
// Se c'è solo il nome
if (name) {
return username ? `${name} (${username})` : name;
}
// Se c'è solo il cognome
if (surname) {
return username ? `${surname} (${username})` : surname;
}
// Se c'è solo username
if (username) {
return username;
}
// Nessun dato disponibile
return '';
},
sulServer() {
@@ -4527,31 +4548,45 @@ module.exports = {
try {
if (!msg) return msg;
if (!!user) {
if (user) {
// Usa replaceAll() per sostituire TUTTE le occorrenze (non solo la prima)
if (msg.includes('{host}')) {
msg = msg.replace('{host}', this.getHostByIdApp(user.idapp));
msg = msg.replaceAll('{host}', this.getHostByIdApp(user.idapp));
}
if (msg.includes('{appname}')) {
msg = msg.replaceAll('{appname}', this.getNomeAppByIdApp(user.idapp));
}
if (msg.includes('{appname}')) msg = msg.replace('{appname}', this.getNomeAppByIdApp(user.idapp));
msg = msg.replace('{username}', user.username);
// msg = await this.checkStr(msg, '{time_exp_reg}', user, 1);
msg = msg.replace('{name}', user.name ? user.name : user.username);
msg = msg.replace('{surname}', user.surname ? user.surname : '');
msg = msg.replace('{urlunsubscribe_user}', this.getUnsubsribeUrl_User(user));
msg = msg.replaceAll('{username}', user.username || '');
msg = msg.replaceAll('{name}', user.name || user.username || '');
msg = msg.replaceAll('{surname}', user.surname || '');
msg = msg.replaceAll('{urlunsubscribe_user}', this.getUnsubsribeUrl_User(user));
msg = msg.replaceAll('{aportador_solidario}', user.aportador_solidario || '');
msg = msg.replace('{aportador_solidario}', user.aportador_solidario ? user.aportador_solidario : '');
if (!!user.profile.link_payment) msg = msg.replace('{link_paypalme}', user.profile.link_payment);
if (!!user.profile.revolut) msg = msg.replace('{revolut}', user.profile.revolut);
if (!!user.profile.payeer_id) msg = msg.replace('{payeer_id}', user.profile.payeer_id);
if (!!user.profile.advcash_id) msg = msg.replace('{advcash_id}', user.profile.advcash_id);
if (!!user.profile.email_paypal) msg = msg.replace('{email_paypal}', user.profile.email_paypal);
if (!!user.profile.note_payment) msg = msg.replace('{note_payment}', user.profile.note_payment);
// Usa optional chaining per evitare errori se user.profile è undefined
if (user.profile?.link_payment) {
msg = msg.replaceAll('{link_paypalme}', user.profile.link_payment);
}
if (user.profile?.revolut) {
msg = msg.replaceAll('{revolut}', user.profile.revolut);
}
if (user.profile?.payeer_id) {
msg = msg.replaceAll('{payeer_id}', user.profile.payeer_id);
}
if (user.profile?.advcash_id) {
msg = msg.replaceAll('{advcash_id}', user.profile.advcash_id);
}
if (user.profile?.email_paypal) {
msg = msg.replaceAll('{email_paypal}', user.profile.email_paypal);
}
if (user.profile?.note_payment) {
msg = msg.replaceAll('{note_payment}', user.profile.note_payment);
}
}
// const cl = getclTelegByidapp(user.idapp);
msg = msg.replace('{link_chathelp}', this.HELP_CHAT);
msg = msg.replaceAll('{link_chathelp}', this.HELP_CHAT);
} catch (e) {
console.log(e);
console.error('Errore in convertSpecialTags:', e);
}
return msg;
@@ -4965,7 +5000,7 @@ module.exports = {
mystr = i18n.__(
'DATE_1DAY',
this.getstrDateLong(myevent.dateTimeStart),
this.getstrTime(myevent.dateTimeStart),
this.getstrTime(myevent.dateTimeStart)
);
} else {
mystr = i18n.__(
@@ -6305,7 +6340,6 @@ module.exports = {
getTokenRandom() {
return crypto.randomBytes(32).toString('hex');
},
async ensureDir(fullnamepath) {

View File

@@ -597,6 +597,7 @@ module.exports = {
MSG_BENV_REGISTRATO: 2020,
MSG_INVITE_WHATSAPP: 2040,
MSG_VERIFICA_TELEGRAM_COMPLETATA: 2050,
MSG_VERIFICA_TELEGRAM_COMPLETATA_NOTIF_INVITANTE: 2060,
},
TypeSend: {