@בנימין14 זה יכול להגרם מהוצאת הדיסק און קי בלי "להוציא" אותו דרך המחשב, זה יכול לשרוף לו את המעבד או משהו כזה (כמדומני שאין לו ממש מעבד אלא משהו צרוב עליו), וכן כל מיני צריבות (כמו הפיכתו לבוטלאודר, אני פעם צרבתי על DOK וינדוס דרך יומי וזה עשה לי אותו הדבר) יכולות ליגרום לזה.
עידו300
-
בקשת מידע | דיסק און קי מוגן מפני כתיבה -
בעיה | מספר עבר לימות המשיח@0772637000 אסור למנוע ניוד, ויש קנסות גם על הפקעת מחירים שמונעת ניוד (לכן הרבה כוכביות הן רק להשכרה, כדי שלא תוכל להכריח אותם לנייד אותו).
הענין הוא שכל זה דוקא אם הקו ברשותך, כאן הקו בכלל לא ברשותך הוא שלהם לגמרי (לא נכנס לאיך הגיע אליהם, רק לטענה שהמחיר לא חוקי) ואף אחד בעולם לא יכול לחייב אותם להביא לך אותו, הם יכולים למכור אותו גם במיליונים אם יהיו קונים, והם יכולים גם לתת אותו לאחר בחינם. -
בירור | nodejs תקינות פונקציהטוב, נהיה לי בלאגן שלם בראש מהכללים האלו.
יש לי המון (9 והיד עוד נטויה) פונקציות עזר למאגר מידע, ויש לי פונקציה שמקבלת רשימת פרמטרים + פונקציות לבדיקה שמתאימות להן ועוד פרמטר שאומר האם לבדוק שכל הפרמטרים ההכרחיים נמצאים או לא.
אני ממש לא יודע מה צריך לבדוק בפונקציות למאגר מידע ומה לא (נראה לי לא אחראי ליצור ככה פונקציות, מצד שני אם בודקים תקינות בפונקציה עצמה, ישר מזדעקים שזה "סקריפט שברירי") או איך לחלק אותן, אשמח לעזרה.
זה קובץ של הולידציה
// סכימה לאימות פרמטרים של מודעה חדשה const adValidationSchema = { phone: {validate: isValidIsraeliPhone, required: true}, type: {validate: checkType, required: true}, min_max_price: {validate: checkNumber, required: false}, ringMode: {validate: checkRingMode, required: false}, area: {validate: checkArea, required: false}, city: {validate: checkCity, required: false}, path: {validate: (path) => typeof path === 'string' && path.trim() !== '', required: false} }; /** * פונקציות DB עם פורמט תשובה אחיד: { success, data, message?, error? } */ function successResponse(data, message = null) { return { success: true, data, message, error: null }; } function errorResponse(error) { return { success: false, data: null, message: null, error }; } // פונקציה לאימות פרמטרים של מודעה חדשה והכנת אובייקט נקי להוספה למסד הנתונים export function validateAdParams(params, checkNecessary = true) { // הגנה מפני קלט ריק if (!params || typeof params !== 'object') { return errorResponse("Invalid parameters input"); } let cleanParams = {}; // בדיקה שכל הפרמטרים שהועברו קיימים בסכימה ותקינים for (const [key, value] of Object.entries(params)) { if (!(key in adValidationSchema) ) {return errorResponse(`Unknown parameter: ${key}`);} const validateFunc = adValidationSchema[key].validate; if (!validateFunc(value)) { return errorResponse(`Invalid value for ${key}`); } cleanParams[key] = value; } if (checkNecessary) { // בדיקה שכל הפרמטרים החיוניים קיימים for (const [key, field] of Object.entries(adValidationSchema)) { if (field.required && !(key in params)) { return errorResponse(`Missing required parameter: ${key}`); } } } return successResponse(cleanParams); }אלו הפונקציות של מסד הנתונים:
import argon from "argon2"; /** * פונקציות DB עם פורמט תשובה אחיד: { success, data, message?, error? } */ function successResponse(data, message = null) { return { success: true, data, message, error: null }; } function errorResponse(error) { return { success: false, data: null, message: null, error }; } /** * ולידציה בסיסית עבור שדות מודעות */ function validateAdData(tableName, data) { const allowedTables = ['ads', 'ad_cities']; if (!allowedTables.includes(tableName)) { throw new Error("שם טבלה לא חוקי"); } const records = Array.isArray(data) ? data : [data]; if (records.length === 0) return true; const validColumns = { ads: ['phone', 'type', 'recording_path', 'min_max_price', 'ring_mode'], ad_cities: ['ad_id', 'city'] }; const columns = validColumns[tableName]; for (const record of records) { const invalidKeys = Object.keys(record).filter(k => !columns.includes(k)); if (invalidKeys.length > 0) { throw new Error(`עמודה לא חוקית בטבלה ${tableName}: ${invalidKeys.join(', ')}`); } } return true; } /** * הוספת רשומה אחת או מרובות לטבלה */ export async function insertRecord(trx, tableName, data) { try { validateAdData(tableName, data); const records = Array.isArray(data) ? data : [data]; if (records.length === 0) { return successResponse([], "אין רשומות להוספה"); } const result = await trx(tableName).insert(records); return successResponse( { insertedId: result[0], affectedRows: records.length }, "רשומות נוספו בהצלחה" ); } catch (err) { console.error("שגיאה בהכנסת נתונים:", err); return errorResponse(err.message || "שגיאה בהכנסת נתונים"); } } /** * פונקציה אוניברסלית לעדכון מודעה ו/או הערים שלה */ export async function updateAdWithCities(knex, adId, adData = {}, cities) { try { return await knex.transaction(async (trx) => { // 1️⃣ עדכון המודעה (אם נשלחו נתונים) if (adData && Object.keys(adData).length > 0) { validateAdData('ads', adData); const updatedRows = await trx('ads') .where({ id: adId }) .update(adData); if (updatedRows === 0) { // חובה לזרוק שגיאה כדי לבטל את הטרנזקציה ולא לשמור בטעות שינויים throw new Error("AD_NOT_FOUND"); } } // 2️⃣ טיפול בערים (רק אם נשלח מערך - גם אם הוא ריק) if (Array.isArray(cities)) { // מחיקת כל הערים הקיימות await trx('ad_cities').where({ ad_id: adId }).del(); const validCities = [...new Set(cities)].filter(c => typeof c === 'string' && c.trim()); // הכנסת הערים החדשות if (validCities.length > 0) { const records = validCities.map(city => ({ ad_id: adId, city: city.trim() })); validateAdData('ad_cities', records); await trx('ad_cities').insert(records); } } return successResponse({ adId }, "העדכון בוצע בהצלחה"); }); } catch (err) { console.error("שגיאה בעדכון מודעה:", err); // תפיסת השגיאה היזומה שלנו if (err.message === "AD_NOT_FOUND") { return errorResponse(`מודעה עם ID ${adId} לא נמצאה`); } return errorResponse(err.message || "שגיאה בעדכון מודעה או הערים"); } } /** * מחזיר את כל המודעות עם הערים הקשורות */ export async function getAllAds(knex) { try { const rows = await knex('ads as a') .leftJoin('ad_cities as c', 'a.id', 'c.ad_id') .select( 'a.*', knex.raw('COALESCE(JSON_ARRAYAGG(c.city), JSON_ARRAY()) as cities') ) .groupBy('a.id'); const formatted = rows.map(row => ({ ...row, cities: (typeof row.cities === 'string' ? JSON.parse(row.cities) : row.cities).filter(Boolean) })); return successResponse(formatted); } catch (err) { console.error("שגיאה בשליפת מודעות:", err); return errorResponse("שגיאה בשליפת מודעות"); } } /** * מחזיר מודעה לפי מזהה */ export async function getAdById(knex, adId) { try { const ad = await knex('ads as a') .leftJoin('ad_cities as c', 'a.id', 'c.ad_id') .select( 'a.*', knex.raw('COALESCE(JSON_ARRAYAGG(c.city), JSON_ARRAY()) as cities') ) .where('a.id', adId) .groupBy('a.id') .first(); if (!ad) return errorResponse(`מודעה עם ID ${adId} לא נמצאה`); const citiesArray = typeof ad.cities === 'string' ? JSON.parse(ad.cities) : ad.cities; return successResponse({ ...ad, cities: citiesArray.filter(Boolean) }); } catch (err) { console.error("שגיאה בשליפת מודעה:", err); return errorResponse("שגיאה בשליפת מודעה"); } } /** * הגדרת שדות מותרים לסינון והאופרטור שלהם */ const FILTER_CONFIG = { phone: '=', type: '=', ringMode: '=', city: '=' }; // פונקציה למציאת מודעות עבור משתמש עם אפשרות לסינון וסטטוס קריאה export async function findAdsForUser( knex, { phone, filters = {}, status = "all"/*, limit = 50, offset = 0 */} ) { if (!phone) return errorResponse("מספר טלפון חסר"); /* const cleanLimit = Math.min(Math.max(parseInt(limit) || 50, 1), 100); const cleanOffset = Math.max(parseInt(offset) || 0, 0);*/ const allowedStatus = ["all", "read", "unread"]; const cleanStatus = allowedStatus.includes(status) ? status : "all"; try { // 1️⃣ הפילטרים מגיעים ישירות מהבקשה const activeFilters = { ...filters }; // 2️⃣ שאילתת בסיס let baseQuery = knex("ads as M"); // 3️⃣ יישום פילטרים קבועים מהקוד Object.entries(FILTER_CONFIG).forEach(([field, operator]) => { const value = activeFilters[field]; if (value !== undefined && value !== null && value !== "") { baseQuery.where(`M.${field}`, operator, value); } }); // 4️⃣ סטטוס קריאה const readSubquery = knex("adsReads") .whereRaw("adsReads.ModhaId = M.Id") .andWhere("adsReads.Phone", phone); if (cleanStatus === "read") baseQuery.whereExists(readSubquery); else if (cleanStatus === "unread") baseQuery.whereNotExists(readSubquery); // 5️⃣ ספירה const countQuery = baseQuery.clone().countDistinct({ total: "M.Id" }).first(); // 6️⃣ שליפת נתונים עם is_read const dataQuery = baseQuery.clone() .select("M.*") .select( knex.raw( `EXISTS ( SELECT 1 FROM adsReads WHERE ModhaId = M.Id AND Phone = ? ) as is_read`, [phone] ) ) .orderBy("M.Id", "desc") /*.limit(cleanLimit) .offset(cleanOffset)*/; // 7️⃣ הרצה מקבילית const [totalResult, rows] = await Promise.all([countQuery, dataQuery]); const totalCount = parseInt(totalResult?.total || 0); return successResponse({ ads: rows.map(r => ({ ...r, is_read: !!r.is_read }))/*, pagination: { total: totalCount, limit: cleanLimit, offset: cleanOffset, hasMore: cleanOffset + rows.length < totalCount }*/ }); } catch (err) { console.error("[findAdsForUser] Error:", err); return errorResponse("שגיאה בשליפת המודעות"); } } /** * מחיקת מודעה (הערים יימחקו אוטומטית בזכות ON DELETE CASCADE ב-DB) * */ export async function deleteAd(knex, adId) { try { // מחיקת המודעה (שים לב: העמודה בטבלת ads נקראת id) const deletedRows = await knex('ads').where({ id: adId }).del(); // אם 0 שורות נמחקו, סימן שהמודעה לא הייתה קיימת if (deletedRows === 0) { return errorResponse(`מודעה עם ID ${adId} לא נמצאה`); } // החזרת תשובת הצלחה בפורמט האחיד return successResponse({ adId }, "המודעה נמחקה בהצלחה"); } catch (err) { console.error("שגיאה במחיקת מודעה:", err); return errorResponse("שגיאה פנימית במחיקת מודעה"); } } // מסמן מודעה כנקראה עבור משתמש מסוים export async function markAdAsRead(knex, phone, adId) { if (!phone || !adId) { return errorResponse("מספר טלפון או מזהה מודעה חסרים"); } try { await knex("adsReads").insert({ ModhaId: adId, Phone: phone }).onconflict(['ModhaId', 'Phone']).ignore(); return successResponse(null, "המודעה סומנה כנקראה"); } catch (err) { console.error("[markAdAsRead] Error:", err); return errorResponse("שגיאה בסימון המודעה כנקראה"); } } export async function findAdByFilter(knex, filters = {}) { if ( !filters || typeof filters !== 'object' || Array.isArray(filters) || Object.keys(filters).length === 0) { return errorResponse("לא סופקו פילטרים חוקיים"); } try { let { city, ...activeFilters } = filters; // 2️⃣ שאילתת בסיס let query = knex("ads as M"); // 3️⃣ יישום פילטרים קבועים מהקוד if (activeFilters.phone) { delete activeFilters.phone; } // טיפול בסינון לפי עיר (תמיכה גם במערך של ערים) if (city) { query.join("ad_cities as C", "C.adId", "M.id"); if (Array.isArray(city)) { query.whereIn("C.city", city); } else { query.where("C.city", city); } } Object.entries(FILTER_CONFIG).forEach(([field, operator]) => { const value = activeFilters[field]; if (value !== undefined && value !== null && value !== "") { // אם הערך הוא מערך, נשתמש ב-IN כדי לאפשר בחירה מרובה if (Array.isArray(value)) { query.whereIn(`M.${field}`, value); } else { query.where(`M.${field}`, operator, value); } } }); // ביצוע השאילתה - שימוש ב-distinct כדי למנוע כפילויות במקרה של JOIN const result = await query .select("M.*") .distinct(); return successResponse({ ads: result }); } catch (error) { console.error("[findAdByFilter] Error:", error); return errorResponse("שגיאה בשליפת המודעה לפי פילטרים"); } } export async function rate(knex, phone, phoneTorating, rating) { if (!phone || !phoneTorating || typeof rating !== 'number' || rating < 1 || rating > 5) { return errorResponse("מספר טלפון או דירוג לא חוקיים"); } try { const hashedPhone = await argon.hash(phone); await knex("rating").insert({ phone: hashedPhone, phoneTorating, rating }).onconflict(['phone', 'phoneTorating']).merge(); return successResponse(null, "הדירוג נוסף/עודכן בהצלחה"); } catch (err) { console.error("[rate] Error:", err); return errorResponse("שגיאה בהוספת הדירוג"); } }תראו את הסקריפט הבא:
<?php include 'db_config.php'; include 'validate_func.php'; $fields = []; $params = []; $types = ""; if (!isset($_REQUEST['phone']) || validate_phone($_REQUEST['phone']) === false) { logRequest('/tmp/request_log.txt', "error - ערך טלפון לא תקין"); respondError("שגיאה במספר טלפון"); } if (isset($_REQUEST['city'])) { if (!validate_city($_REQUEST['city'])) { respondError("city לא תקין"); } $fields[] = "city"; $params[] = $_REQUEST['city']; $types .= "s"; } // --- 2. betShemesh --- if (isset($_REQUEST['betShemesh']) && trim($_REQUEST['betShemesh']) !== "") { // חייב להופיע city קודם if (!isset($_REQUEST['city']) || $_REQUEST['city'] !== "בית שמש") { respondError("betShemesh חייב להגיע עם city"); } if (!validate_betShemesh($_REQUEST['betShemesh'])) { respondError("betShemesh לא תקין"); } $fields[] = "betShemesh"; $params[] = $_REQUEST['betShemesh']; $types .= "s"; } // --- 3. region --- if (isset($_REQUEST['region']) && trim($_REQUEST['region']) !== "") { // חייבים להיות city + betShemesh if (!isset($_REQUEST['city'], $_REQUEST['betShemesh'])) { respondError("region חייב להגיע עם city ו-betShemesh"); } if (!validate_region($_REQUEST['region'], $_REQUEST['city'], $_REQUEST['betShemesh'])) { respondError("region לא תקין"); } $fields[] = "region"; $params[] = $_REQUEST['region']; $types .= "s"; } if (isset($_REQUEST['buyorrent']) && validate_buyorrent($_REQUEST['buyorrent'])) { $fields[] = "buyorrent"; $params[] = $_REQUEST['buyorrent']; $types .= "s"; } if (isset($_REQUEST['room']) && validate_room($_REQUEST['room']) !== false) { $fields[] = "room"; $params[] = $_REQUEST['room']; $types .= "d"; } if (!empty($fields) && count($fields) === count($params)) { $fields[] = "phone"; $params[] = $_REQUEST['phone']; $types .= "s"; $placeholders = implode(", ", array_fill(0, count($fields), "?")); $sql = "INSERT INTO subcrib (" . implode(", ", $fields) . ") VALUES ($placeholders)"; } else { respondError("בקשה לא תקינה"); } // --- 3. התחברות למסד נתונים --- mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // הפעלת זריקת חריגות אוטומטית לשגיאות try { $conn = new mysqli($host, $username, $password, $dbname); $conn->set_charset("utf8mb4"); $stmt = $conn->prepare($sql); $stmt->bind_param($types, ...$params); if ($stmt->execute()) { logRequest('/tmp/request_log.txt', "ok - הרישום נוסף בהצלחה"); header('Content-Type: application/json; charset=utf-8'); echo json_encode([ "status" => "success", "message" => "הרישום נוסף בהצלחה" ], JSON_UNESCAPED_UNICODE); } else { logRequest('/tmp/request_log.txt', "error - שגיאה"); respondError("שגיאה בהוספת רישום"); } } catch (mysqli_sql_exception $e) { logRequest('/tmp/request_log.txt', "Database Connection Failed: " . $e->getMessage()); // למערכת חיצונית נחזיר הודעה גנרית respondError("שגיאה"); } finally { // חשוב לסגור את החיבורים בסוף if (isset($stmt)) { $stmt->close(); } $conn->close(); }קוד יפיפה, מובן, מוגן, אף מתכנת לא יכול להשתמש בפונקציה לא לפי הכללים וא"א לעקוף את ההגנות על המסד נתונים. מה יותר טוב מזה?
-
בקשת מידע | תשלום ג'ימני או AI סטודיו@ע-ה-דכו-ע תודה
מעניין אותי, מה הסכום הכי גבוה שיצא לך לראות? -
בקשת מידע | תשלום ג'ימני או AI סטודיו@ע-ה-דכו-ע ז"א שיעלה 0.07 או שה0.04 זה הסכום הסופי?
אם זה יוצא 0.07 אז טוב שאתה אומר, כי ראיתי 0.24 אמרתי לא נורא, זה לא כזה יקר, אבל אם זה רק חלק מהסכום צריך בהחלט לשקול שוב.נשמע שהסכום הוא הסכום ה- סה"כ, ככה שזה לא אמור לאצת כ"כ יקר, לא?
-
בקשת מידע | תשלום ג'ימני או AI סטודיויש הבדל בין ג'ימני API וapi key של aistudio?
אני כיום משתמש בAI studio ומשום מה נגמרו לי הטוקנים לשימוש. אז אני רוצה לשלם כדי שאוכל להמשיך להשתמש.
השאלה מה צריך לעשות? עושה רושם שזה 2 דברים שונים. מה אני צריך לעשות ומה הכי משתלם/מקצועי.
תודה
-
בקשת מידע | מערכת לקמפיין פורים@A0533057932 מבחינת מה? אחריות? הרבה עבודה?
אגב, זו לא דרישה שלי, זה הלקוח רוצה... זה שיקול שלו אם להאמין בחורים או לא, זה כבר לא קשור אליי... -
בקשת מידע | מערכת לקמפיין פורים@A0533057932 כתב בבקשת מידע | מערכת לקמפיין פורים:
ועדכון אוף ליין הוא מאד בעיה במנגנון המצינג של נדרים
יש את זה https://matara.pro/nedarimplus/ApiDocumentation.html?v=61, אני חושב שפותר את ענין האופליין
לגבי כל השאר, לא מכיר את המנגנון שלהם, אתה מכיר אותו יו רטוב ממני כנראה...
-
בקשת מידע | מערכת לקמפיין פורים@A0533057932 כתב בבקשת מידע | מערכת לקמפיין פורים:
או מנגנון אחר להריץ קוד קיים
זו הנקודה, גוגל סקריפט זה פתרון טוב.
@A0533057932 כתב בבקשת מידע | מערכת לקמפיין פורים:
חוץ מהחלק שבו בחור יכול לעדכן תרומות אוף ליין שלו
גם זה כלום עבודה.
@A0533057932 כתב בבקשת מידע | מערכת לקמפיין פורים:
כמובן הכוונה שלי אחרי שפותחים את מנגנון המצינג של נדרים
אין לי מושג, אם היו פותחים מנגנון מצ'ינג, למה צריך את ימות המשיח?
-
בקשת מידע | מערכת לקמפיין פורים@A0533057932
לא צריך שרת...
למה צריך? -
בקשת מידע | מערכת לקמפיין פורים@דוד-ארן תבדוק איתם אם הם יכולים לשלוח את פרטי התרומה גם לשיטס ואז נוכל ליצור שיטס וממנו להשמיע את הנתונים בקוים של ימות המשיח.
-
בקשת מידע | מערכת לקמפיין פורים -
בקשת מידע | מערכת לקמפיין פורים@דוד-ארן קצת יותר לא יודע כמה צריך לבדוק
-
בקשת מידע | מערכת לקמפיין פורים@דוד-ארן קצת לחוץ, אבדוק מה אפשר לעשות, אבל אתה צריך לדעת שזה לא יעלה 200 שקל...
-
בקשת מידע | מערכת לקמפיין פורים@דוד-ארן נכון.
אם תרצה שיתעדכן מפלטפורמה אחרת ככל הנראה תצטרך API. -
בקשת מידע | מערכת לקמפיין פורים@דוד-ארן הבאתי כמה קישורים תחפש בהודעות קודמות
זה לדעתי הכי רלוונטי https://f2.freeivr.co.il/topic/93/מודול-התרמות
-
בקשת מידע | מערכת לקמפיין פורים@kasnik גם אפשר, שלוחת API או שלוחת קבלת נתונים.
לא רואה שום בעיה בזה -
בקשת מידע | מערכת לקמפיין פורים@A0533057932 לא ראיתי שביקש אופליין, איפה ביקש?
ואם משתמשים בקו של ימות המשיח, זה תמיד אונליין, לא?
-
בקשת מידע | מערכת לקמפיין פורים@kasnik לא צריך db הבאתי מספיק קישורים גם בלי db. מקסימום שיטס.
-
בקשת מידע | מערכת לקמפיין פוריםיש אולי גם זה
https://f2.freeivr.co.il/topic/19988/השנה-ההתרמה-שלכם-תראה-אחרתוהיה פעם עוד אחד
אפשר עם גוגל סקריפט לפי זה
https://f2.freeivr.co.il/topic/18469/הוספת-התאמת-והשמעת-נתוני-רישום-דרך-גוגל-סקריפט-קבלת-נתונים-בשילוב-הודעות-אישיות