Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-02-20 15:22:46 +03:00
parent d4583c17d2
commit 50f87e3290
5 changed files with 69 additions and 16 deletions

View File

@@ -9,8 +9,9 @@ func (m *GraphMailer) SendPasswordResetMail(toEmail string, resetURL string) err
<p>Merhaba,</p> <p>Merhaba,</p>
<p>Parolanızı sıfırlamak için aşağıdaki bağlantıya tıklayın:</p> <p>Parolanızı sıfırlamak için aşağıdaki bağlantıya tıklayın:</p>
<p> <p>
<a href="%s">%s</a> <a href="%s">Parolayı sıfırla</a>
</p> </p>
<p style="font-size:12px;color:#666;">Bağlantı: %s</p>
<p>Bu bağlantı <strong>30 dakika</strong> geçerlidir ve tek kullanımlıktır.</p> <p>Bu bağlantı <strong>30 dakika</strong> geçerlidir ve tek kullanımlıktır.</p>
`, resetURL, resetURL) `, resetURL, resetURL)

View File

@@ -2,12 +2,28 @@ package security
import ( import (
"os" "os"
"strings"
) )
func BuildResetURL(token string) string { func BuildResetURL(token string) string {
base := os.Getenv("FRONTEND_URL") base := os.Getenv("APP_FRONTEND_URL")
if base == "" {
base = os.Getenv("FRONTEND_URL")
}
if base == "" { if base == "" {
base = "http://localhost:9000" base = "http://localhost:9000"
} }
return base + "/password-reset/" + token base = strings.TrimRight(base, "/")
// If base already points to password-reset, just append token if needed.
if strings.Contains(base, "/password-reset") {
if strings.HasSuffix(base, "/password-reset") || strings.HasSuffix(base, "/password-reset/") ||
strings.HasSuffix(base, "/#/password-reset") || strings.HasSuffix(base, "/#/password-reset/") {
return strings.TrimRight(base, "/") + "/" + token
}
return base
}
if strings.Contains(base, "#") {
return base + "/password-reset/" + token
}
return base + "/#/password-reset/" + token
} }

View File

@@ -6,9 +6,7 @@ import (
"bssapp-backend/internal/security" "bssapp-backend/internal/security"
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"os"
"strings" "strings"
"time" "time"
) )
@@ -84,11 +82,7 @@ func ForgotPasswordHandler(
// ------------------------------------------------------- // -------------------------------------------------------
// 5⃣ Reset URL (PLAIN token) // 5⃣ Reset URL (PLAIN token)
// ------------------------------------------------------- // -------------------------------------------------------
resetURL := fmt.Sprintf( resetURL := security.BuildResetURL(plain)
"%s/password-reset/%s",
os.Getenv("FRONTEND_URL"),
plain,
)
// ------------------------------------------------------- // -------------------------------------------------------
// 6⃣ Mail gönder (fail olsa bile enumeration yok) // 6⃣ Mail gönder (fail olsa bile enumeration yok)

View File

@@ -14,7 +14,6 @@ import (
"io" "io"
"log" "log"
"net/http" "net/http"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -462,11 +461,7 @@ func SendPasswordResetMailHandler(
`, userID, hash, expires) `, userID, hash, expires)
// 🔗 URL → PLAIN // 🔗 URL → PLAIN
resetURL := fmt.Sprintf( resetURL := security.BuildResetURL(plain)
"%s/password-reset/%s",
os.Getenv("FRONTEND_URL"),
plain,
)
_ = mailer.SendPasswordResetMail(email, resetURL) _ = mailer.SendPasswordResetMail(email, resetURL)

View File

@@ -2533,6 +2533,50 @@ export const useOrderEntryStore = defineStore('orderentry', {
console.log(`🧭 Order mode set edildi → ${mode}`) console.log(`🧭 Order mode set edildi → ${mode}`)
} }
, ,
// Sync only header-related fields from the form before submit.
syncHeaderFromForm(form) {
if (!form || typeof form !== 'object') return
const keys = [
'OrderHeaderID',
'OrderTypeCode',
'ProcessCode',
'OrderNumber',
'OrderDate',
'AverageDueDate',
'Description',
'InternalDescription',
'CurrAccTypeCode',
'CurrAccCode',
'CurrAccDescription',
'DocCurrencyCode',
'LocalCurrencyCode',
'ExchangeRate',
'OfficeCode',
'CreatedUserName',
'CreatedDate',
'LastUpdatedUserName',
'LastUpdatedDate',
'PaymentTerm',
'WarehouseCode',
'StoreCode'
]
const patch = {}
for (const k of keys) {
if (Object.prototype.hasOwnProperty.call(form, k)) {
patch[k] = form[k]
}
}
if (Object.keys(patch).length > 0) {
this.header = {
...(this.header || {}),
...patch
}
}
}
,
/* =========================================================== /* ===========================================================
🟦 submitAllReal (v12.1c — FINAL / CLEAN + PRE-VALIDATE) 🟦 submitAllReal (v12.1c — FINAL / CLEAN + PRE-VALIDATE)
----------------------------------------------------------- -----------------------------------------------------------
@@ -2553,6 +2597,9 @@ export const useOrderEntryStore = defineStore('orderentry', {
// 🔒 Kontrollü submit → route leave guard susar // 🔒 Kontrollü submit → route leave guard susar
this.isControlledSubmit = true this.isControlledSubmit = true
// ✅ Formdaki header alanlarını store'a taşı
this.syncHeaderFromForm?.(form)
const isNew = this.mode === 'new' const isNew = this.mode === 'new'
const { header, lines } = this.buildFinalOrderJson() const { header, lines } = this.buildFinalOrderJson()