תודה לכל העונים.
מסיכום של הדברים, החלטתי להפריד כל משתמש לdb נפרד
מקווה שאסתדר עם השיוך של כל בקשה לdb הנכון, אם לא אפתח נושא חדש.
תודה לכל העונים.
מסיכום של הדברים, החלטתי להפריד כל משתמש לdb נפרד
מקווה שאסתדר עם השיוך של כל בקשה לdb הנכון, אם לא אפתח נושא חדש.
יש לי תוכנה (אינטרנטית) שכתבתי בעבר ללקוח ספציפי, וכעת הוא הפנה אלי חבר שרוצה את זה גם, והתוכנה עצמה צריכה שדרוג מקיף, וכחלק מהשדרוג אני מייעל את העבודה מול הdb עצמו (mysql).
השאלה שלי כעת היא, זה די ברור לי (משום מה) שאני צריך להשתמש במסד נתונים אחד ל2 הלקוחות, אז קודם כל האם זה נכון?
ודבר שני, חשבתי לבצע את החלוקה, שלכל רשומה יהיה עמודה נוספת לצד עמודת הid שתכיל את הid_client, ועל פיו תתבצע ההפרדה בין הנתונים של הלקוחות השונים. האם זה הדרך הנכונה?
(מצד שני יש שם טבלאות שקשה לי לקבל את זה שהם יהיו משותפים בטבלה אחת לכל הלקוחות, כמו טבלת לקוחות (של הלקוח), טבלת מוצרים וכו')
תודה מראש על המענה
אני עדיין לא מצליח להוסיף את הפקד הזה, ניסיתי בכמה צורות, ואפילו העתקתי מאפליקציית הדגמה שמצאתי שם ועדיין מציג לי שגיאות ולא נותן לי לקמפל
@dovid כתב בכיצד להוסיף את FilterDataGrid לפקד DataGrid?:
יש בדף שנתת מקטע "איך משתמשים"
האמן לי שניסיתי...
התקנתי את החבילה מנוגט
הוספתי בטופס הרלוונטי את מרחב השמות
xmlns:control="http://filterdatagrid.control.com/2021"
נתקעתי בקטע של "Control", אני לא מצליח להבין היכן זה צריך להיכנס, בתוך הDataGrid, כפקד נפרד (אני חדש בWPF למרות שהמלצת לי לעשות את זה כבר מההתחלה, רק עכשיו החלטתי להיות אמיץ ולעבור)
<control:FilterDataGrid
FilterLanguage="English" DateFormatString="d" ShowStatusBar="True" ShowElapsedTime="False"
ExcludeFields="lastname,age,manager" ...
זה הxaml של הDataGrid
<DataGrid x:Name="dataGridInfo" d:ItemsSource="{d:SampleData ItemCount=5}" Margin="43,153,43,128" CanUserAddRows="False" IsTextSearchEnabled="True" IsTextSearchCaseSensitive="True" AutoGenerateColumns="False" ColumnWidth="Auto" FontSize="14" BorderBrush="Azure" >
<DataGrid.Columns>
<DataGridTextColumn Header="מזהה" Binding="{Binding Id}" IsReadOnly="True" Width="60" />
<DataGridCheckBoxColumn Header="פעיל" Binding="{Binding active}" IsReadOnly="True" Width="40"/>
<DataGridTextColumn Header="שם משפחה" Binding="{Binding idFamily}" IsReadOnly="True" Width="90" />
<DataGridTextColumn Header="שם פרטי" Binding="{Binding idName}" IsReadOnly="True" Width="90" />
<DataGridTemplateColumn Header="המלצה">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:StarRatingControl x:Name="starRatingControl" Rating="{Binding favorite}" IsHitTestVisible="False" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
אני מנסה להוסיף את הספרייה הזו עבור סינון הנתונים בפקד הDataGrid בחלון בWPF.
התקנתי את הספריה מnuget, אבל אינני מצליח להבין איך להשתמש בה בפועל בפרויקט שלי.
@OdedDvir כתב באפשרויות סינון מתקדמות בפקד DataGrid בWPF:
זה נראה פרוייקט פעיל עם ממשק דומה לשל אקסל: https://github.com/macgile/DataGridFilter
ניסיתי כעת להשתמש בזה, ולא הצלחתי.
התקנתי מנוגט את FilterDataGrid.
הוספתי xmlns:control="http://filterdatagrid.control.com/2021" בXAML
ומכאן זה פשוט מציג לי שגיאות, איך שלא ניסיתי להוסיף את הControl
<control:FilterDataGrid
FilterLanguage="English" DateFormatString="d" ShowStatusBar="True" ShowElapsedTime="False"
ExcludeFields="lastname,age,manager" ...
אני רוצה להוסיף תרשים לטופס שלי, שבלחיצת כפתור יוצג תרשים קו משהו כמו זה, שיציג את הנתונים מהעמודה sum מהdataTableThaslomim בצורה גרפית,
אני רוצה שיהיה בגרף נקודה עבור כל רשומה (בתמונה: 300, 700, 0, 550, 700), ובנוסף יהיה קו שיציג את הממוצע, וקו שמציג את הנטיה הלינארית (כמו הקו המקווקו בתמונה, אולי זה נקרא "קו מגמה").
מגיגול קצר הבנתי שיש כל מיני חבילות לתרשימים, התקנתי את OxyPlot, אבל לא הצלחתי להוסיף איתה בפועל, וגם אני לא בטוח שהיא הכי טובה
אשמח למידע על חבילות לזה (wpf + c#), עדיף לי יעילות והגדרה קלה שלא אסתבך עם זה יותר מידי.
@צדיק-תמים לא ממש הבנתי את זה מלמעלה, בעז"ה היום בערב אני אנסה לעשות את זה כפי שהסברת ואעדכן, תודה רבה.
שלום, יש לי קובץ node js שמכיל מספר פונקציות, ואני רוצה לפצל כל פונקציה (היינו כל פעילות מסויימת) לקובץ נפרד בשביל שיהיה מסודר, וכן להעביר את הראוטרים לקובץ אחד, שממנו יופעלו כל הקבצים,
חלק מהפונקציות נקראות באמצעות הדפדפן, וחלק מימות המשיח עם הספריה, והסתבכתי בענין.
אני מצרף קטע עם דוגמה בכדי שיהיה קל להבין למה אני מתכוון,
הראוטרים של chk וShare הם מודולי API של ימות שמשתמשים בספרייה, והראוטר הכללי וYemotLogin משמשים לגישה דרך הדפדפן.
בנוסף, אני רוצה להיות מסוגל לקרוא לפונקציה שנקראת licenseVerification מכל הקבצים ללא שאצטרך להעתיק אותה לכל אחד.
אשמח לעזרה והסבר מה אני צריך להשאיר בקובץ הראשי של הראוטרים, ומה אני צריך לכלול בכל קובץ שמשתמש בספרייה לימות המשיח, ומה בפונקציות הרגילות.
import { YemotRouter } from 'yemot-router2';
import express from 'express';
import axios from 'axios';
import fs from 'fs';
import { promises as fsPromises } from 'fs';
export const app = express();
export const router = YemotRouter({
printLog: true,
uncaughtErrorHandler: (error, call) => {
console.log(`Uncaught error from ${call.phone}. error stack: ${error.stack}`);
return call.id_list_message([{ type: 'text', data: 'השרת נתקל בשגיאה פנה למנהל' }]);
}
});
router.post('/chk', callHandler);
router.post('/Share', sharing);
app.get('/YemotLogin', (req, res) => yemotLogin(req, res));
app.get('/', function (req, res) {
res.send('אין גישה');
});
app.use(express.urlencoded({ extended: true }));
app.use(router);
const port = 3000;
app.listen(port, () => console.log(`The express server is now running and listening on port ${port}`));
const url_yemot_api = 'https://www.call2all.co.il/ym/api/';
async function yemotLogin(req, res) {
console.log('yemotLogin');
res.send('Blocked');
}
function licenseVerification(apiDID) {
if (apiDID) {
console.log('status: ', 'true');
return true;
} else {
console.log('status: ', 'blocked');
return false;
}
}
async function sharing(call) {
await call.id_list_message([{
type: 'text',
data: 'הפעולה הושלמה'
}]);
}
async function callHandler(call) {
if (await licenseVerification(call.ApiDID) === true) {
return call.id_list_message([{
type: 'text',
data: 'גישה מאופשרת'
}]);
} else {
return call.id_list_message([{
type: 'text',
data: 'המספר שלכם חסום לגישה'
}]);
}
}
אכן מצאתי כאן https://help.syncfusion.com/wpf/datagrid/filtering?cs-save-lang=1&cs-lang=csharp#programmatic-filtering משהו כזה בתשלום, ויש להם תוכנית חינמית רק שלא הצלחתי להבין האם זה לתמיד או רק ל30 יום וא"כ האם אחרי 30 יום אני יותר לא אוכל להשתמש בזה בתוכנה...
@dovid כתב בשמירת נתונים לSQLlite מפקד DataGrid בWPF:
ותציין באיזה שורה השגיאה קורית.
כאן
adapter.Update(dataTable) (שורה 46)
איזה חבילות/ספריות מותקנות?
אני התקנתי את החבילה השניה, כנראה שהיא מתקינה אוטומטית את הראשונה
האם ניתן בפקד DataGrid בWPF לסנן נתונים באופן מתקדם כמו שיש לדוגמה בטפסי אקסס שניתן ללחוץ על כותרת השדה ואפשר לבחור סינון לפי שווה ל... אינו מכיל וכו'? ואם לא, האם מישהו מכיר משהו מן המוכן שמאפשר לממש את זה?
חשבתי לעשות פקד רשימה משולבת שבו יהיה ניתן לבחור שדה מרשימת השדות, ולידו יהיה תיבת טקסט שתכיל את הערך, ואז כפתורי רדיו שיאפשר לבחור את סוג הסינון, אבל זה נראה לי הרבה עבודה, ואולי יש משהו מוכן כבר
אני משתמש בSQLlite עבור תוכנה מסוג WPF בC#, ואני טוען את הנתונים של טבלה מסוימת לפקד DataGrid עם הפונקציה LoadData, ואני רוצה לאפשר למשתמש לערוך את הנתונים שבפקד בטופס, ואז לעשות כפתור שמירה של הנתונים שנערכו חזרה לדאטהבייס באמצעות הפונקציה SaveChangesToDatabase, אבל אני מקבל שגיאה "שלא ניתן לגשת לקובץ שנזרק" היכן הטעות שלי?
private SQLiteDataAdapter adapter;
private DataTable dataTable;
private DataView dataView;
public static string softwareLibrary = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
public static string dbFilePath = Path.Combine(softwareLibrary, "calls.db");
public static string connectionString = $"Data Source={dbFilePath}";
private void LoadData()
{
using (SQLiteConnection connection = new SQLiteConnection(Globals.connectionString))
{
connection.Open();
string filterId = txtId.Text.Trim();
string filterTime = txtTime.Text.Trim();
string selectSql = "SELECT * FROM tCalls WHERE CallId LIKE '%" + filterId + "%' AND CallTime LIKE '%" + filterTime + "%'";
using (SQLiteCommand cmd = new SQLiteCommand(selectSql, connection))
{
adapter = new SQLiteDataAdapter(cmd);
SQLiteCommandBuilder commandBuilder = new SQLiteCommandBuilder(adapter);
dataTable = new DataTable();
adapter.Fill(dataTable);
this.dataGridCalls.ItemsSource = dataTable.DefaultView;
}
connection.Close();
}
}
private void SaveChangesToDatabase()
{
try
{
if (dataTable != null && dataTable.GetChanges() != null)
{
using (SQLiteConnection connection = new SQLiteConnection(Globals.connectionString))
{
connection.Open();
using (SQLiteCommandBuilder commandBuilder = new SQLiteCommandBuilder(adapter))
{
adapter.Update(dataTable);
}
connection.Close();
}
dataTable.AcceptChanges();
}
}
catch (Exception ex)
{
MessageBox.Show($"An error occurred while saving changes: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@A0533057932 כתב בעזרה בהגדרת כללים ברשת וירטואלית באורקל:
תתיר גישה אליו רק מהרשת הפנימית
ותפנה אליו דרך פרוקסי (ממליץ גם בלי קשר לאבטחה)
ולאתר תתיר גישה רק דרך IP מסויים דרך הNGINX עצמו
אתה מתכוון לwebmin נכון?
תכל'ס לא הבנתי מה אני יכול למחוק בכללים של הרשת שהבאתי למעלה
יש לי שרתים באורקל קלאוד שיושבים מאחורי רשת פרטית שלהם, הכללים של הרשת הם מה שבתמונות למטה, מה אני צריך למחוק בכדי שהשרת יהיה מאובטח מצד אחד ומה אני צריך להשאיר בכדי שהשרת יהיה פעיל מצד שני,
אני מתחבר אליו עם SSH מרשת נטפרי עם כתובת ip משתנה, (בפורט 22)
בנוסף יש לי אפאצ'י שהבנתי שמשתמש בפורט 80/433 ואני רוצה שיהיה פתוח,
יש node שמאזין בפורט 4536 אבל הגישה אליו היא באמצעות פרוקסי הפוך מהאפאצ'י, ולא ישירות לאייפי/פורט.
בנוסף מותקן webmin שמאזין בפורט 8689 ואליו הגדרתי גישה רק מכתובות איפי מותרות ואני עורך את זה כל פעם מחדש לכתובת האייפי הנוכחית שלי.
@צדיק-תמים קודם כל תודה על העזרה!
handlerReceive זה מגיע אחרי הבאג, וזה עובד מצויין, שבמקרה שלא נמצאו אסימונים בקריאה לgetAir או שהמשתמש בחר 2 להמשיך כרגיל זה יוצר את תסריט השיחה הרגיל,
getAir קורא נתונים מקובץ בשרת, כעת שמתי בו 2 שורות בגוף הקוד, ובודק האם העמודה השניה תואמת למס' הזיהוי של המשתמש במערכת, ובאם הוא מוצא הוא מחזיר את השורות כמערך של אובייקטים כל שורה באובייקט נפרד עם העמודות שלה.
אני מקווה שכעת זה מספיק,כי אני לא באמת יודע מה להביא כי כבר getAir עצמה נראית בסדר במחשב, ורק בטלפון זה לא מושמע
async function callHandler(call) {
const isAir = await getAir(call);
console.log('isAir', isAir.join('\n'));
if (isAir != false) {
var message = '';
if (isAir.length > 1) {
const messages = isAir.map(row => `אסימון מסוג ${row.type} בשווי ${row.value}`).join(' וכן את ');
message = `יש לכם ${isAir.length} אסימונים פעילים ${messages}`;
} else if (isAir.length === 1) {
const row = isAir[0];
message = `יש לכם אסימון אחד פעיל מסוג ${row.type} בשווי ${row.value}`;
} else {
console.log('No matching rows found');
}
console.log('message', message);
const choiceAction = await call.read([{
type: 'text',
data: message + `למימוש הקישו 1 להמשך הפעילות הקישו 2`
}], 'tap', {
max_digits: 1,
digits_allowed: [1, 2],
allow_empty: false,
sec_wait: 12
});
console.log('choiceAction', choiceAction);
if (choiceAction == 1) {
call.id_list_message([{
type: 'text',
data: `אפשרות זו עדיין לא פעילה`
}]);
} else if (choiceAction == 2) {
handlerReceive(call);
}
} else {
handlerReceive(call);
}
}
async function getAir(call) {
const user = "079555555";
//let apiEnterID = call?.ApiEnterID || "";
//let [apiEnterIDType, apiEnterIDValue] = apiEnterID !== "" ? apiEnterID.split('-') : ["ללא", call.ApiPhone];
let apiEnterIDValue = '0559777777';
try {
//const filePath = `${user}/air.ini`;
//const fileContent = await fs.readFileSync(filePath, 'utf-8');
const fileContent = `afhnrcl4b4r24k9,0559777777,0559777777,יוסי,12,זהב,1,רגיל,1
7bun3eqdznlpk86,0559777777,0559777777,יוסי,12,זהב,1,רגיל,1`;
const dataArray = fileContent.split('\n').filter(Boolean);
const matchingRows = dataArray.filter(row => {
const columns = row.split(',');
return columns[2] === apiEnterIDValue;
});
if (matchingRows.length === 0) {
console.log('No matching rows found');
return false;
}
console.log('matching rows');
const resultArray = matchingRows.map(row => {
const columns = row.split(',');
return {
IdAction: columns[0],
phone: columns[1],
idphone: columns[2],
name: columns[3],
typeIndex: columns[4],
type: columns[5],
valueIndex: columns[6],
value: columns[7],
sum: columns[8]
};
});
return resultArray;
} catch (error) {
console.error('Error:', error.message);
return false;
}
}
@צדיק-תמים אתה צודק, הבעיה שזה לא נשלח לימות המשיח היתה אחרת, עכ"פ עדיין למרות שההודעה נשלחת לימות המשיח ומופיעה בלוג, עדיין נשמע שקט,
מה שמעניין ששמתי לב שהבעיה מתרחש רק כשיש יותר מאסימון אחד, וכן כשאני מעתיק את הטקסט שמופיע בלוג של ימות ומריץ את זה ישר עליו, זה עובד מצויין, אבל כשהטקסט משורשר באמצעות הקוד, זה משמיע שקט, כך שנראה שהבעיה היא בלוגיקה של הקטע שבשורות 11,12 (ואני מדגיש שגם אז זה מודפס לקונסול ונשלח לימות המשיח כרגיל רק לא מושמע)
זה הפונקציה המלאה
async function callHandler(call) {
const isAir = await getAir(call);
console.log('isAir', isAir.join('\n'));
if (isAir != false) {
var message = '';
if (isAir.length > 1) {
const messages = isAir.map(row => `אסימון מסוג ${row.type} בשווי ${row.value}`).join(' וכן את ');
message = `יש לכם ${isAir.length} אסימונים פעילים ${messages}`;
} else if (isAir.length === 1) {
const row = isAir[0];
message = `יש לכם אסימון אחד פעיל מסוג ${row.type} בשווי ${row.value}`;
} else {
console.log('No matching rows found');
}
console.log('message', message);
const choiceAction = await call.read([{
type: 'text',
data: message + `למימוש הקישו 1 להמשך הפעילות הקישו 2`
}], 'tap', {
max_digits: 1,
digits_allowed: [1, 2],
allow_empty: false,
sec_wait: 12
});
console.log('choiceAction', choiceAction);
if (choiceAction == 1) {
call.id_list_message([{
type: 'text',
data: `אפשרות זו עדיין לא פעילה`
}]);
} else if (choiceAction == 2) {
handlerReceive(call);
}
} else {
handlerReceive(call);
}
}
@צדיק-תמים זהו, שהפלט של console.log('message', message);
הוא "יש לכם 3 אסימונים פעילים לחצו על 1 להשמעה חוזרת ו 2 ליציאה",
זה רץ בתוך פונקציה async
אני משתמש בספריה לתקשורת עם ימות המשיח בnode, ובקטע הזה, הmessage נשלח לימות ריק, היינו אני לא שומע את ההודעה, אבל זה כן נותן לי את אפשרויות ההקשה,
if (isAir != false) {
var message = '';
if (isAir.length > 1) {
message = `יש לכם ${isAir.length} אסימונים פעילים לחצו על 1 להשמעה חוזרת ו 2 ליציאה`;
} else if (isAir.length === 1) {
message = 'יש לכם אסימון אחד לחצו על 1 להשמעה חוזרת ו 2 ליציאה';
} else {
console.log('No matching rows found');
}
console.log('message', message);
const choiceAction = await call.read([{
type: 'text',
data: message
}], 'tap', {
max_digits: 1,
digits_allowed: [1, 2],
allow_empty: false,
sec_wait: 8
});
console.log('choiceAction', choiceAction);
}
אני חושב שזה בגלל האסינכרוניות, למרות שההדפסה לקונסול כן יוצאת תקינה, איך אני מוודא שרק לאחר סיום הif תתבצע הקריאה לread?
(אני מכיר קצת קולבקים אבל לא הבנתי איך להכניס את זה במקרה הזה בלי להשתמש בעוד פונקציות)
@dovid תודה! זה אכן עזר
מי אמר שלינוקס זה מסובך? רק מי שלא הכיר את פורום תחומים והמשתמשים הצדיקים שלו.