Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-04-22 11:19:36 +03:00
parent e6ae925f1c
commit d2387bc221
10 changed files with 855 additions and 543 deletions

View File

@@ -18,6 +18,7 @@ import (
"time"
"github.com/gorilla/mux"
"github.com/lib/pq"
"golang.org/x/crypto/bcrypt"
)
@@ -497,25 +498,65 @@ func UserCreateRoute(db *sql.DB) http.HandlerFunc {
// ROLES
for _, role := range payload.Roles {
_, _ = tx.Exec(queries.InsertUserRole, newID, role)
role = strings.TrimSpace(role)
if role == "" {
continue
}
if _, err := tx.Exec(queries.InsertUserRole, newID, role); err != nil {
log.Printf("USER ROLE INSERT ERROR user_id=%d role=%q err=%v", newID, role, err)
http.Error(w, "Rol eklenemedi", http.StatusInternalServerError)
return
}
}
// DEPARTMENTS
for _, d := range payload.Departments {
_, _ = tx.Exec(queries.InsertUserDepartment, newID, d.Code)
code := strings.TrimSpace(d.Code)
if code == "" {
continue
}
if _, err := tx.Exec(queries.InsertUserDepartment, newID, code); err != nil {
log.Printf("USER DEPARTMENT INSERT ERROR user_id=%d department=%q err=%v", newID, code, err)
http.Error(w, "Departman eklenemedi", http.StatusInternalServerError)
return
}
}
// PIYASALAR
for _, p := range payload.Piyasalar {
_, _ = tx.Exec(queries.InsertUserPiyasa, newID, p.Code)
code := strings.TrimSpace(p.Code)
if code == "" {
continue
}
if _, err := tx.Exec(queries.InsertUserPiyasa, newID, code); err != nil {
log.Printf("USER PIYASA INSERT ERROR user_id=%d piyasa=%q err=%v", newID, code, err)
http.Error(w, "Piyasa eklenemedi", http.StatusInternalServerError)
return
}
}
// NEBIM
for _, n := range payload.NebimUsers {
_, _ = tx.Exec(queries.InsertUserNebim, newID, n.Username)
username := strings.TrimSpace(n.Username)
if username == "" {
continue
}
if _, err := tx.Exec(queries.InsertUserNebim, newID, username); err != nil {
log.Printf("USER NEBIM INSERT ERROR user_id=%d username=%q err=%v", newID, username, err)
http.Error(w, "Nebim kullanıcısı eklenemedi", http.StatusInternalServerError)
return
}
}
if err := tx.Commit(); err != nil {
if pe, ok := err.(*pq.Error); ok {
log.Printf(
"USER CREATE COMMIT ERROR user_id=%d code=%s detail=%s constraint=%s table=%s err=%v",
newID, pe.Code, pe.Detail, pe.Constraint, pe.Table, err,
)
} else {
log.Printf("USER CREATE COMMIT ERROR user_id=%d err=%v", newID, err)
}
http.Error(w, "Commit başarısız", http.StatusInternalServerError)
return
}

View File

@@ -32,13 +32,31 @@ func GetProductPricingListHandler(w http.ResponseWriter, r *http.Request) {
limit := 500
if raw := strings.TrimSpace(r.URL.Query().Get("limit")); raw != "" {
if parsed, err := strconv.Atoi(raw); err == nil && parsed > 0 && parsed <= 10000 {
if parsed, err := strconv.Atoi(raw); err == nil && parsed > 0 && parsed <= 500 {
limit = parsed
}
}
afterProductCode := strings.TrimSpace(r.URL.Query().Get("after_product_code"))
page := 1
if raw := strings.TrimSpace(r.URL.Query().Get("page")); raw != "" {
if parsed, err := strconv.Atoi(raw); err == nil && parsed > 0 {
page = parsed
}
}
filters := queries.ProductPricingFilters{
Search: strings.TrimSpace(r.URL.Query().Get("q")),
ProductCode: splitCSVParam(r.URL.Query().Get("product_code")),
BrandGroup: splitCSVParam(r.URL.Query().Get("brand_group_selection")),
AskiliYan: splitCSVParam(r.URL.Query().Get("askili_yan")),
Kategori: splitCSVParam(r.URL.Query().Get("kategori")),
UrunIlkGrubu: splitCSVParam(r.URL.Query().Get("urun_ilk_grubu")),
UrunAnaGrubu: splitCSVParam(r.URL.Query().Get("urun_ana_grubu")),
UrunAltGrubu: splitCSVParam(r.URL.Query().Get("urun_alt_grubu")),
Icerik: splitCSVParam(r.URL.Query().Get("icerik")),
Karisim: splitCSVParam(r.URL.Query().Get("karisim")),
Marka: splitCSVParam(r.URL.Query().Get("marka")),
}
rows, err := queries.GetProductPricingList(ctx, limit+1, afterProductCode)
pageResult, err := queries.GetProductPricingPage(ctx, page, limit, filters)
if err != nil {
if isPricingTimeoutLike(err, ctx.Err()) {
log.Printf(
@@ -63,38 +81,24 @@ func GetProductPricingListHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Urun fiyatlandirma listesi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
hasMore := len(rows) > limit
if hasMore {
rows = rows[:limit]
}
nextCursor := ""
if hasMore && len(rows) > 0 {
nextCursor = strings.TrimSpace(rows[len(rows)-1].ProductCode)
}
log.Printf(
"[ProductPricing] trace=%s success user=%s id=%d limit=%d after=%q count=%d has_more=%t next=%q duration_ms=%d",
"[ProductPricing] trace=%s success user=%s id=%d page=%d limit=%d count=%d total=%d total_pages=%d duration_ms=%d",
traceID,
claims.Username,
claims.ID,
pageResult.Page,
limit,
afterProductCode,
len(rows),
hasMore,
nextCursor,
len(pageResult.Rows),
pageResult.TotalCount,
pageResult.TotalPages,
time.Since(started).Milliseconds(),
)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
if hasMore {
w.Header().Set("X-Has-More", "true")
} else {
w.Header().Set("X-Has-More", "false")
}
if nextCursor != "" {
w.Header().Set("X-Next-Cursor", nextCursor)
}
_ = json.NewEncoder(w).Encode(rows)
w.Header().Set("X-Total-Count", strconv.Itoa(pageResult.TotalCount))
w.Header().Set("X-Total-Pages", strconv.Itoa(pageResult.TotalPages))
w.Header().Set("X-Page", strconv.Itoa(pageResult.Page))
_ = json.NewEncoder(w).Encode(pageResult.Rows)
}
func buildPricingTraceID(r *http.Request) string {
@@ -124,3 +128,20 @@ func isPricingTimeoutLike(err error, ctxErr error) bool {
strings.Contains(e, "no connection could be made") ||
strings.Contains(e, "failed to respond")
}
func splitCSVParam(raw string) []string {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
parts := strings.Split(raw, ",")
out := make([]string, 0, len(parts))
for _, p := range parts {
p = strings.TrimSpace(p)
if p == "" {
continue
}
out = append(out, p)
}
return out
}