From 485c75f06c9a55ea54106073b3e7741682d26110 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 10 Apr 2023 10:42:20 +0200 Subject: [PATCH 01/12] Role-Editor: UI for Participant and User --- src/RoleEditor/App.config | 3 + src/RoleEditor/App.xaml | 9 ++ src/RoleEditor/App.xaml.cs | 17 ++++ src/RoleEditor/AssemblyInfo.cs | 10 +++ src/RoleEditor/MainWindow.xaml | 126 +++++++++++++++++++++++++++ src/RoleEditor/MainWindow.xaml.cs | 40 +++++++++ src/RoleEditor/Resources.Designer.cs | 63 ++++++++++++++ src/RoleEditor/Resources.resx | 101 +++++++++++++++++++++ src/RoleEditor/RoleEditor.csproj | 25 ++++++ src/RoleEditor/RoleEditor.sln | 25 ++++++ 10 files changed, 419 insertions(+) create mode 100644 src/RoleEditor/App.config create mode 100644 src/RoleEditor/App.xaml create mode 100644 src/RoleEditor/App.xaml.cs create mode 100644 src/RoleEditor/AssemblyInfo.cs create mode 100644 src/RoleEditor/MainWindow.xaml create mode 100644 src/RoleEditor/MainWindow.xaml.cs create mode 100644 src/RoleEditor/Resources.Designer.cs create mode 100644 src/RoleEditor/Resources.resx create mode 100644 src/RoleEditor/RoleEditor.csproj create mode 100644 src/RoleEditor/RoleEditor.sln diff --git a/src/RoleEditor/App.config b/src/RoleEditor/App.config new file mode 100644 index 0000000..49cc43e --- /dev/null +++ b/src/RoleEditor/App.config @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/RoleEditor/App.xaml b/src/RoleEditor/App.xaml new file mode 100644 index 0000000..7f5413e --- /dev/null +++ b/src/RoleEditor/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/src/RoleEditor/App.xaml.cs b/src/RoleEditor/App.xaml.cs new file mode 100644 index 0000000..6d8bf95 --- /dev/null +++ b/src/RoleEditor/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace RoleEditor +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/src/RoleEditor/AssemblyInfo.cs b/src/RoleEditor/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/src/RoleEditor/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/src/RoleEditor/MainWindow.xaml b/src/RoleEditor/MainWindow.xaml new file mode 100644 index 0000000..ec3d72d --- /dev/null +++ b/src/RoleEditor/MainWindow.xaml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -70,7 +90,22 @@ - + + + + + + + + + + + + + + + + @@ -110,14 +150,38 @@ @@ -138,12 +202,36 @@ diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs index dc9b2bb..8d37ed8 100644 --- a/src/RoleEditor/MainWindow.xaml.cs +++ b/src/RoleEditor/MainWindow.xaml.cs @@ -90,5 +90,45 @@ namespace RoleEditor { } + + private void menuItemDeleteParticipant_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemNewParticipant_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemNewUser_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemDeleteUser_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemNewRole_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemDeleteRole_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemNewSecurable_Click(object sender, RoutedEventArgs e) + { + + } + + private void menuItemDeleteSecurable_Click(object sender, RoutedEventArgs e) + { + + } } } diff --git a/src/RoleEditor/Resources.Designer.cs b/src/RoleEditor/Resources.Designer.cs index 6c70a23..b62f446 100644 --- a/src/RoleEditor/Resources.Designer.cs +++ b/src/RoleEditor/Resources.Designer.cs @@ -59,5 +59,115 @@ namespace RoleEditor { resourceCulture = value; } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] about { + get { + object obj = ResourceManager.GetObject("about", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] add { + get { + object obj = ResourceManager.GetObject("add", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] arrow_left_green { + get { + object obj = ResourceManager.GetObject("arrow_left_green", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] businessman { + get { + object obj = ResourceManager.GetObject("businessman", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] delete2 { + get { + object obj = ResourceManager.GetObject("delete2", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] disk_blue { + get { + object obj = ResourceManager.GetObject("disk_blue", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] id_card { + get { + object obj = ResourceManager.GetObject("id_card", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] key1 { + get { + object obj = ResourceManager.GetObject("key1", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] key1_add { + get { + object obj = ResourceManager.GetObject("key1_add", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] lock_preferences { + get { + object obj = ResourceManager.GetObject("lock_preferences", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] safe { + get { + object obj = ResourceManager.GetObject("safe", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/src/RoleEditor/Resources.resx b/src/RoleEditor/Resources.resx index 4fdb1b6..2d7da8b 100644 --- a/src/RoleEditor/Resources.resx +++ b/src/RoleEditor/Resources.resx @@ -1,101 +1,154 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\about.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\add.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\arrow_left_green.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\businessman.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\delete2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\disk_blue.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\id_card.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\key1.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\key1_add.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\lock_preferences.ico;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\safe.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/src/RoleEditor/Resources/about.png b/src/RoleEditor/Resources/about.png new file mode 100644 index 0000000000000000000000000000000000000000..c2738bf4672a6ec9c30e9efd8d9b35897f2ed724 GIT binary patch literal 1331 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 literal 0 HcmV?d00001 diff --git a/src/RoleEditor/Resources/disk_blue.png b/src/RoleEditor/Resources/disk_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..1abc0e76a4a0eb048daec6c22240359fb5703213 GIT binary patch literal 1313 zcmV++1>X9JP)WdKueATc)}PH%P~GB7YQATc>QF*iCiHXti7F)%Pez_sxJ000McNliru z(*hC|87uYwIhFtb010qNS#tmY3h)2`3h)6!tTdPa000DMK}|sb0I`n?{9y$E00enS zL_t(|+O<{9iyTE1|5a6Y&&>Apd}VhwB)i!UJxIiZAQ(^rikOR_2SL1w5Ih+a1^)y8 z01xUZQSjnj5X4JB1<{Q`#l@_)U_6}?mLnRIgVL_xG+LVx$m6a*55j8vx1_Pl;fJiB247|Bjk{5$Ea0EcjumwVa zCUaxqmD~FII@;~_logY{SzKH^qKxmuLgn)*05}?k7j=pxP6U88E0@b~U3W~yBt6_l zij1jZaD8O)kp;v*o2j*?FieC3ZVcf2{#ft`n8(RJ0$>J|)yDv6&#-feCUQ68VI({= z*zWEwdcEEhEt3xCC}KcMQIu-lBVj5%X#qJQ%R2fbxrQvDUazB4sf@#OM9FA>Oj&B> zviOR%O^;ci$p>^4F0CX{h+)4g7d2flbiopBsc4@_-0L(`qCf1(|6~{v3yQ2}D%5cc z(kzN-{oWwOhhOd?O7>VEF+0;H73Z<_R(7n6oY^WP0EhOJfTT*Fq(}hh*9w78*JxSi z=IXr5+=w+iYC4jQTH>GYd$echKSQ5zGWc*_{fxt*Mh96F60TWe5}*YvA4#Yq04fJl z5)||!I@L)FIFU7r5(+g=7rI!j_DM4%LOJ;&s#OEdV(xvaq#Uxz0C$`vQOXz>rnyY# z?TFV&ij43o2n6(SEyUG#p24?2{e@n)gI4=K)t4S>K^cwN1{(DS=I5KZ_3KT%`gw#x zX$CVz7mu9vv9{IzpD-ovbeh*90!Sz!{@A{aXWzI9Z>bLNR2}bK^srDZqUhI9@T+i& z0gP9I4g$DA1%;x6ns26ZCIg@hHg3irXIiR^FOlF1>b1IP&*h`l zYN2!3CYp#A&xLj=vZzb4WuDG0_~eN<@yd<(X)gzIYpl|GbV~d;gKqx; XrJ6_bcRR`r00000NkvXXu0mjfq-|A@ literal 0 HcmV?d00001 diff --git a/src/RoleEditor/Resources/id_card.png b/src/RoleEditor/Resources/id_card.png new file mode 100644 index 0000000000000000000000000000000000000000..70e78af3addfc60469d8b0c21bf384548b9ba998 GIT binary patch literal 1436 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 literal 0 HcmV?d00001 diff --git a/src/RoleEditor/Resources/key1_add.png b/src/RoleEditor/Resources/key1_add.png new file mode 100644 index 0000000000000000000000000000000000000000..06057ef91c66f016c64e76d2698fea26499381c3 GIT binary patch literal 1273 zcmVWdKBPATlr@MrC3kGB7YRATcvKGB!FhH6SZ6F)%P5uA z(Jd}6Y$&prXbdBn2|t!?M&cit5>&Q?WfDFIn;oMz| zfUq0_?L7D(^d2iN>bI08-RkN^I5ea9d2PUKN#eu4Ac)qWk$fHtUAi)YupJ-iH$1-4 zHZ%qU7xI}3Qg>oTkRgjd2fRLza0sHjbkFWfK-#cY2*gwvSR+FIQDQ30I>;EBS_sK2 z_4mo(bOdgnk0f%i-h)sFLVvVEwOzpb3yWYQk6{~L(68Ibi-H{nJ?R18)Obg@osJP3 zG`cASr~Si;#hAEDxDJIT{SJyv9902m3_+Xf{sL<@nbk_8pwU4!od>^LE|nk{ zMBAUe?yYOIG6F#bIh!?*v?;jKDs(4vq?pwqYiJk^P61nU*1FWqN4~l^@0<_!6|0~p z>s#h>(Gevu8d2?XO3$uOL$)cM#mK03)@!qW{TPQ2v~OUBE^&0#qcA9<>S|MMmHYW) zF*^95H_%g_sr|d^5a4;M{maD6qC*RsoU;eEvGeqraAAiiD6Bqi_HtnboOin+zZ?>s zj$b;49mb^YM~Oxc(UUXZWR-xv`@H>cetQ_nB#ifVonGR*`M2n-#VdmsjD(CA5HeOo zh_`{@UFw>{bX3w&5oyIw#64Q6G#o(df~(?w@yjPjv`(U?v^WS%kJ1bW1Wth*siQi@ zVA|oJZt+37x}CH)Q?=x|kMchgPzN5*%R?$=X-kwD85&j#DHfPGK|LG?TlbXWoAR)J zKNQy_NJ0#1mqlRU;PcObOu0aso560|roe1g$)LDBr299S5k-gw9=s_I@06TGZ)D%H zZpXHdaY&R_JZ5H7mR^AsiOnrdLPCU^vLIR;7d+nEV^ge*KZ^)RO0RR8}K=m z3{;ZHiNI-bpzJixEMCj5gn(mlZt!<>Owcy=^{M^&V{!mzms-1`6GY;CCG>6)-$eLQ j;!(Y;4(%(&T2=f7TuKpdk<8PT00000NkvXXu0mjfal1ge literal 0 HcmV?d00001 diff --git a/src/RoleEditor/Resources/lock_preferences.ico b/src/RoleEditor/Resources/lock_preferences.ico new file mode 100644 index 0000000000000000000000000000000000000000..4128cdbc5df96b1c62f881c6551b39f454b7301e GIT binary patch literal 26694 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 literal 0 HcmV?d00001 diff --git a/src/RoleEditor/Resources/safe.png b/src/RoleEditor/Resources/safe.png new file mode 100644 index 0000000000000000000000000000000000000000..2bd364d3f149a8bb36a17a4e19d225a69dfb9843 GIT binary patch literal 1100 zcmV-S1he~zP)WdKBPATcx`PH%P~GB7YQATl#LH90ymG$1Q5F)%Q>U7vUW000McNliru z(*pw(7ByUNYexV8010qNS#tmY3labT3lag+-G2N4000DMK}|sb0I`n?{9y$E00X2+ zL_t(|+O<{BPg6kpDF;Q$pc6$wzHiBYg90cxT22YoH=bH0t+JQ^TP44cf`eY>;YH#0jsOLWRj zsYhvSY|L9KmAVy0>E7Pn4pu6a=0c(Hg=LACXL#-X$jC^(E`p(-uE|wXhI_QMp{EOeQ17yhf~B;x!P?7mLLORaM`H!{M(CR}lmg6B7?u`8L29 zw99I>Iy6lq{>NtGO+qjRD5Q4G;8nu?{e6S`&GGSZpA7`LT<&E@M~BA1LIGgtu>n>a zh9SI@y&S`Ue`2s#1_J{edlV);13f_iC2Yv&^8yeJ9ISl~gK4>2zAbxc~@;w6wI4*Xt#> z+fB>M%i@fx1ZWaeiX`Iji5?(}i;M8m0s^$w)>dk7Zx_J1T!F&_(M3dLB#tF8lSprH zHd|X;)ZgDPfDszRJeA6jswU{hRh>S4c9G3y7kfqc@d2C660^t*ks>V%1OkNE16 zY(@S=A`we07VGEDk6G?8xq_RE#^5?z`-qE0LvNt{?yde zn|k(I>QTZoh`1v}9J*pT; literal 0 HcmV?d00001 diff --git a/src/RoleEditor/RoleEditor.csproj b/src/RoleEditor/RoleEditor.csproj index 31347be..21970fb 100644 --- a/src/RoleEditor/RoleEditor.csproj +++ b/src/RoleEditor/RoleEditor.csproj @@ -5,8 +5,39 @@ net6.0-windows enable true + Resources\lock_preferences.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True From aa0c1d81d93e04c5a8e76c057956f0d8937fa630 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 12 Apr 2023 12:08:40 +0200 Subject: [PATCH 04/12] added models and a database controller --- misc/create_schema.sql | 8 ++++ src/RoleEditor/MainWindow.xaml | 2 +- src/RoleEditor/MainWindow.xaml.cs | 36 +++++++++++++++ src/RoleEditor/RoleEditor.csproj | 5 ++ src/RoleEditor/RoleEditor.sln | 14 +++++- src/brecal.model/DbEntity.cs | 27 +++++++++++ src/brecal.model/IDBManager.cs | 20 ++++++++ src/brecal.model/Participant.cs | 35 ++++++++++++++ src/brecal.model/Role.cs | 30 ++++++++++++ src/brecal.model/RoleAssignment.cs | 21 +++++++++ src/brecal.model/Securable.cs | 28 ++++++++++++ src/brecal.model/SecurableAssignment.cs | 19 ++++++++ src/brecal.model/User.cs | 29 ++++++++++++ src/brecal.model/brecal.model.csproj | 9 ++++ src/brecal.mysql/DBManager.cs | 61 +++++++++++++++++++++++++ src/brecal.mysql/brecal.mysql.csproj | 17 +++++++ 16 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 src/brecal.model/DbEntity.cs create mode 100644 src/brecal.model/IDBManager.cs create mode 100644 src/brecal.model/Participant.cs create mode 100644 src/brecal.model/Role.cs create mode 100644 src/brecal.model/RoleAssignment.cs create mode 100644 src/brecal.model/Securable.cs create mode 100644 src/brecal.model/SecurableAssignment.cs create mode 100644 src/brecal.model/User.cs create mode 100644 src/brecal.model/brecal.model.csproj create mode 100644 src/brecal.mysql/DBManager.cs create mode 100644 src/brecal.mysql/brecal.mysql.csproj diff --git a/misc/create_schema.sql b/misc/create_schema.sql index 8df7d30..7bf326f 100644 --- a/misc/create_schema.sql +++ b/misc/create_schema.sql @@ -175,6 +175,8 @@ CREATE TABLE `role` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL DEFAULT '0' COMMENT 'unique role name', `description` VARCHAR(255) NULL DEFAULT '0' COMMENT 'role description', + `created` DATETIME NULL DEFAULT current_timestamp(), + `modified` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(), PRIMARY KEY (`id`), UNIQUE INDEX `name` (`name`) ) @@ -187,6 +189,8 @@ ENGINE=InnoDB CREATE TABLE `securable` ( `id` INT(10) UNSIGNED NOT NULL, `name` VARCHAR(50) NOT NULL DEFAULT '', + `created` DATETIME NULL DEFAULT current_timestamp(), + `modified` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(), PRIMARY KEY (`id`), UNIQUE INDEX `name` (`name`) ) @@ -199,6 +203,8 @@ CREATE TABLE `user_role_map` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` INT(10) UNSIGNED NOT NULL DEFAULT 0, `role_id` INT(10) UNSIGNED NOT NULL DEFAULT 0, + `created` DATETIME NULL DEFAULT current_timestamp(), + `modified` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(), PRIMARY KEY (`id`), INDEX `FK_USER_ROLE` (`user_id`), INDEX `FK_ROLE_USER` (`role_id`), @@ -214,6 +220,8 @@ CREATE TABLE `role_securable_map` ( `id` INT(10) UNSIGNED NOT NULL, `role_id` INT(10) UNSIGNED NOT NULL, `securable_id` INT(10) UNSIGNED NOT NULL, + `created` DATETIME NULL DEFAULT current_timestamp(), + `modified` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(), PRIMARY KEY (`id`), INDEX `FK_ROLE_SECURABLE` (`role_id`), INDEX `FK_SECURABLE_ROLE` (`securable_id`), diff --git a/src/RoleEditor/MainWindow.xaml b/src/RoleEditor/MainWindow.xaml index 237d08f..8d24419 100644 --- a/src/RoleEditor/MainWindow.xaml +++ b/src/RoleEditor/MainWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:RoleEditor" mc:Ignorable="d" - Title="Bremen calling admin editor" Height="600" Width="800" Icon="Resources/lock_preferences.ico"> + Title="Bremen calling admin editor" Height="600" Width="800" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded"> diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs index 8d37ed8..53313db 100644 --- a/src/RoleEditor/MainWindow.xaml.cs +++ b/src/RoleEditor/MainWindow.xaml.cs @@ -14,6 +14,8 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using System.Collections.ObjectModel; +using brecal.model; namespace RoleEditor { @@ -22,11 +24,36 @@ namespace RoleEditor /// public partial class MainWindow : Window { + #region private fields + + private ObservableCollection _participants = new ObservableCollection(); + private ObservableCollection _roles = new ObservableCollection(); + private ObservableCollection _securables = new ObservableCollection(); + private ObservableCollection _users = new ObservableCollection(); + private ObservableCollection _assignedRoles = new ObservableCollection(); + private ObservableCollection _assignedSecurables = new ObservableCollection(); + + #endregion + + #region Construction / Loading + public MainWindow() { InitializeComponent(); } + private void Window_Loaded(object sender, RoutedEventArgs e) + { + // try database connection + + // load all participants + + // load all roles + + } + + #endregion + #region button callbacks private void buttonParticipantSave_Click(object sender, RoutedEventArgs e) @@ -71,6 +98,8 @@ namespace RoleEditor #endregion + #region listbox selection callbacks + private void listBoxParticipant_SelectionChanged(object sender, SelectionChangedEventArgs e) { @@ -91,6 +120,10 @@ namespace RoleEditor } + #endregion + + #region menuitem callbacks + private void menuItemDeleteParticipant_Click(object sender, RoutedEventArgs e) { @@ -130,5 +163,8 @@ namespace RoleEditor { } + + #endregion + } } diff --git a/src/RoleEditor/RoleEditor.csproj b/src/RoleEditor/RoleEditor.csproj index 21970fb..936e6bb 100644 --- a/src/RoleEditor/RoleEditor.csproj +++ b/src/RoleEditor/RoleEditor.csproj @@ -21,6 +21,11 @@ + + + + + diff --git a/src/RoleEditor/RoleEditor.sln b/src/RoleEditor/RoleEditor.sln index e3f05ce..6b98d6e 100644 --- a/src/RoleEditor/RoleEditor.sln +++ b/src/RoleEditor/RoleEditor.sln @@ -3,7 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33516.290 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoleEditor", "RoleEditor.csproj", "{8A8CB0D3-7728-468E-AB11-E811BA5B5BC0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoleEditor", "RoleEditor.csproj", "{8A8CB0D3-7728-468E-AB11-E811BA5B5BC0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "brecal.model", "..\brecal.model\brecal.model.csproj", "{F3BC5ADC-BF57-47DC-A5D5-CC4A13857DEE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "brecal.mysql", "..\brecal.mysql\brecal.mysql.csproj", "{E88F908B-48C9-46BD-A3AE-C36FBE9EDF1F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +19,14 @@ Global {8A8CB0D3-7728-468E-AB11-E811BA5B5BC0}.Debug|Any CPU.Build.0 = Debug|Any CPU {8A8CB0D3-7728-468E-AB11-E811BA5B5BC0}.Release|Any CPU.ActiveCfg = Release|Any CPU {8A8CB0D3-7728-468E-AB11-E811BA5B5BC0}.Release|Any CPU.Build.0 = Release|Any CPU + {F3BC5ADC-BF57-47DC-A5D5-CC4A13857DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3BC5ADC-BF57-47DC-A5D5-CC4A13857DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3BC5ADC-BF57-47DC-A5D5-CC4A13857DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3BC5ADC-BF57-47DC-A5D5-CC4A13857DEE}.Release|Any CPU.Build.0 = Release|Any CPU + {E88F908B-48C9-46BD-A3AE-C36FBE9EDF1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E88F908B-48C9-46BD-A3AE-C36FBE9EDF1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E88F908B-48C9-46BD-A3AE-C36FBE9EDF1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E88F908B-48C9-46BD-A3AE-C36FBE9EDF1F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/brecal.model/DbEntity.cs b/src/brecal.model/DbEntity.cs new file mode 100644 index 0000000..19b74b2 --- /dev/null +++ b/src/brecal.model/DbEntity.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public class DbEntity + { + /// + /// DB primary key + /// + public uint Id { get; set; } + + /// + /// Creation timestamp, if null record is unsaved + /// + public DateTime? Created { get; set; } + + /// + /// Modified timestamp, if null record was never modified + /// + public DateTime? Modified { get; set; } + + } +} diff --git a/src/brecal.model/IDBManager.cs b/src/brecal.model/IDBManager.cs new file mode 100644 index 0000000..0b1f44e --- /dev/null +++ b/src/brecal.model/IDBManager.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public interface IDBManager + { + + void Load(Action prepareAction, Action loadAction); + + Task ExecuteScalar(Action prepareAction); + + Task ExecuteNonQuery(Action prepareAction); + + } +} diff --git a/src/brecal.model/Participant.cs b/src/brecal.model/Participant.cs new file mode 100644 index 0000000..49e2de0 --- /dev/null +++ b/src/brecal.model/Participant.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public class Participant : DbEntity + { + #region Properties + + public string? Name { get; set; } + + public string? Street { get; set; } + + public string? PostalCode { get; set; } + + public string? City { get; set; } + + public uint Flags { get; set; } + + #endregion + + #region overrides + + public override string ToString() + { + return this.Name ?? $"{base.Id} - {this.GetType().Name}"; + } + + #endregion + + } +} diff --git a/src/brecal.model/Role.cs b/src/brecal.model/Role.cs new file mode 100644 index 0000000..bc182bd --- /dev/null +++ b/src/brecal.model/Role.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public class Role : DbEntity + { + + #region Properties + + public string? Name { get; set; } + + public string? Description { get; set; } + + #endregion + + #region overrides + + public override string ToString() + { + return this.Name ?? $"{base.Id} - {this.GetType().Name}"; + } + + #endregion + + } +} diff --git a/src/brecal.model/RoleAssignment.cs b/src/brecal.model/RoleAssignment.cs new file mode 100644 index 0000000..3fd46b5 --- /dev/null +++ b/src/brecal.model/RoleAssignment.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public class RoleAssignment : DbEntity + { + + #region Properties + + public Role? AssignedRole { get; set; } + + public User? AssignedUser { get; set; } + + #endregion + + } +} diff --git a/src/brecal.model/Securable.cs b/src/brecal.model/Securable.cs new file mode 100644 index 0000000..906e8e8 --- /dev/null +++ b/src/brecal.model/Securable.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public class Securable : DbEntity + { + + #region Properties + + public string? Name { get; set; } + + #endregion + + #region overrides + + public override string ToString() + { + return this.Name ?? $"{base.Id} - {this.GetType().Name}"; + } + + #endregion + + } +} diff --git a/src/brecal.model/SecurableAssignment.cs b/src/brecal.model/SecurableAssignment.cs new file mode 100644 index 0000000..7a68bd2 --- /dev/null +++ b/src/brecal.model/SecurableAssignment.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace brecal.model +{ + public class SecurableAssignment : DbEntity + { + #region Properties + + public Role? AssignedRole { get; set; } + + public Securable? AssignedSecurable { get; set; } + + #endregion + } +} diff --git a/src/brecal.model/User.cs b/src/brecal.model/User.cs new file mode 100644 index 0000000..3358dcb --- /dev/null +++ b/src/brecal.model/User.cs @@ -0,0 +1,29 @@ +namespace brecal.model +{ + public class User : DbEntity + { + #region Properties + + public string? Firstname { get; set; } + + public string? Lastname { get; set; } + + public string Username { get; set; } = ""; + + public string? PasswordHash { get; set; } + + public string? APIKey { get; set; } + + #endregion + + #region overrides + + public override string ToString() + { + return this.Username ?? $"{base.Id} - {this.GetType().Name}"; + } + + #endregion + + } +} \ No newline at end of file diff --git a/src/brecal.model/brecal.model.csproj b/src/brecal.model/brecal.model.csproj new file mode 100644 index 0000000..132c02c --- /dev/null +++ b/src/brecal.model/brecal.model.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/src/brecal.mysql/DBManager.cs b/src/brecal.mysql/DBManager.cs new file mode 100644 index 0000000..f85f5b9 --- /dev/null +++ b/src/brecal.mysql/DBManager.cs @@ -0,0 +1,61 @@ +using brecal.model; +using MySqlConnector; +using System.Data; +using System.Runtime.CompilerServices; + +namespace brecal.mysql +{ + public class DBManager : IDBManager + { + private static string _connectionString = ""; + + + public async void Generic() + { + await using var connection = new MySqlConnection("Server=myserver;User ID=mylogin;Password=mypass;Database=mydatabase"); + await connection.OpenAsync(); + + using var command = new MySqlCommand("SELECT field FROM table;", connection); + await using var reader = await command.ExecuteReaderAsync(); + while (await reader.ReadAsync()) + Console.WriteLine(reader.GetString(0)); + } + + public async void Load(Action prepareAction, Action loadAction) + { + await using MySqlConnection connection = new MySqlConnection(_connectionString); + await connection.OpenAsync(); + using MySqlCommand cmd = new MySqlCommand(); + cmd.Connection = connection; + prepareAction(cmd); + MySqlDataReader reader = await cmd.ExecuteReaderAsync(); + loadAction(reader); + reader.Close(); + } + + public async Task ExecuteScalar(Action prepareAction) + { + await using MySqlConnection connection = new MySqlConnection(_connectionString); + await connection.OpenAsync(); + + using MySqlCommand cmd = new MySqlCommand(); + cmd.Connection = connection; + prepareAction(cmd); + object? result = await cmd.ExecuteScalarAsync(); + return result; + } + + public async Task ExecuteNonQuery(Action prepareAction) + { + await using MySqlConnection connection = new MySqlConnection(_connectionString); + await connection.OpenAsync(); + + using MySqlCommand cmd = new MySqlCommand(); + cmd.Connection = connection; + prepareAction(cmd); + int result = await cmd.ExecuteNonQueryAsync(); + return result; + } + + } +} \ No newline at end of file diff --git a/src/brecal.mysql/brecal.mysql.csproj b/src/brecal.mysql/brecal.mysql.csproj new file mode 100644 index 0000000..786b11e --- /dev/null +++ b/src/brecal.mysql/brecal.mysql.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + From bbb986260ca9e6b064d6a492f9e076d572d5f279 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sat, 15 Apr 2023 18:58:24 +0200 Subject: [PATCH 05/12] Speicher-Logik erweitern --- src/RoleEditor/MainWindow.xaml.cs | 27 ++++-- src/brecal.model/DbEntity.cs | 11 ++- src/brecal.model/IDBManager.cs | 4 +- src/brecal.model/Participant.cs | 121 ++++++++++++++++++++++++ src/brecal.model/Role.cs | 10 ++ src/brecal.model/RoleAssignment.cs | 10 ++ src/brecal.model/Securable.cs | 10 ++ src/brecal.model/SecurableAssignment.cs | 11 +++ src/brecal.model/User.cs | 10 ++ src/brecal.mysql/DBManager.cs | 29 ++---- 10 files changed, 214 insertions(+), 29 deletions(-) diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs index 53313db..2767da5 100644 --- a/src/RoleEditor/MainWindow.xaml.cs +++ b/src/RoleEditor/MainWindow.xaml.cs @@ -16,6 +16,7 @@ using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; using brecal.model; +using brecal.mysql; namespace RoleEditor { @@ -26,12 +27,13 @@ namespace RoleEditor { #region private fields - private ObservableCollection _participants = new ObservableCollection(); - private ObservableCollection _roles = new ObservableCollection(); - private ObservableCollection _securables = new ObservableCollection(); - private ObservableCollection _users = new ObservableCollection(); - private ObservableCollection _assignedRoles = new ObservableCollection(); - private ObservableCollection _assignedSecurables = new ObservableCollection(); + private readonly ObservableCollection _participants = new ObservableCollection(); + private readonly ObservableCollection _roles = new ObservableCollection(); + private readonly ObservableCollection _securables = new ObservableCollection(); + private readonly ObservableCollection _users = new ObservableCollection(); + private readonly ObservableCollection _assignedRoles = new ObservableCollection(); + private readonly ObservableCollection _assignedSecurables = new ObservableCollection(); + private DBManager? _dbManager; #endregion @@ -45,11 +47,20 @@ namespace RoleEditor private void Window_Loaded(object sender, RoutedEventArgs e) { // try database connection + try + { + _dbManager = new(); - // load all participants + // load all participants - // load all roles + // load all roles + } + catch (Exception ex) + { + MessageBox.Show($"Database connection couldn't be established: {ex.Message}"); + this.Close(); + } } #endregion diff --git a/src/brecal.model/DbEntity.cs b/src/brecal.model/DbEntity.cs index 19b74b2..4a098b8 100644 --- a/src/brecal.model/DbEntity.cs +++ b/src/brecal.model/DbEntity.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace brecal.model { - public class DbEntity + public abstract class DbEntity { /// /// DB primary key @@ -23,5 +23,14 @@ namespace brecal.model /// public DateTime? Modified { get; set; } + /// + /// Each database entity must be able to save itself to the database + /// + public abstract void Save(IDBManager manager); + + /// + /// Each entity must be able to delete itself + /// + public abstract void Delete(IDBManager manager); } } diff --git a/src/brecal.model/IDBManager.cs b/src/brecal.model/IDBManager.cs index 0b1f44e..15ff592 100644 --- a/src/brecal.model/IDBManager.cs +++ b/src/brecal.model/IDBManager.cs @@ -10,7 +10,9 @@ namespace brecal.model public interface IDBManager { - void Load(Action prepareAction, Action loadAction); + delegate List LoadFunc(T entity); + + Task> Load(Action prepareAction, LoadFunc loadAction); Task ExecuteScalar(Action prepareAction); diff --git a/src/brecal.model/Participant.cs b/src/brecal.model/Participant.cs index 49e2de0..0e68936 100644 --- a/src/brecal.model/Participant.cs +++ b/src/brecal.model/Participant.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -22,6 +23,126 @@ namespace brecal.model #endregion + #region abstract method implementation + + // TODO: Diese Funktionen in die Basisklasse verschieben und die SetUpdate SetCreate SetDelete + // abstract machen + + public async override void Save(IDBManager manager) + { + if (this.Created.HasValue) + await manager.ExecuteNonQuery(this.SetUpdate); + else + await manager.ExecuteNonQuery(this.SetCreate); + } + + public async override void Delete(IDBManager manager) + { + await manager.ExecuteNonQuery(this.SetDelete); + } + + #endregion + + #region public static methods + + public static async Task> LoadAll(IDBManager manager) + { + List loadResultList = await manager.Load(SetLoadQuery, LoadElems); + List result = new List(); + foreach (Participant p in loadResultList.Cast()) + result.Add(p); + return result; + } + + #endregion + + #region parameter funcs + + public static void SetLoadQuery(IDbCommand cmd) + { + cmd.CommandText = "SELECT id, name, street, postal_code, city, flags, created, modified FROM participant"; + } + + public void SetUpdate(IDbCommand cmd) + { + cmd.CommandText = "UPDATE participant set name = @NAME, street = @STREET, postal_code = @POSTAL_CODE, city = @CITY, flags = @FLAGS WHERE id = @ID"; + this.SetParameters(cmd); + } + + public void SetCreate(IDbCommand cmd) + { + cmd.CommandText = "INSERT INTO participant (name, street, postal_code, city, flags) VALUES ( @NAME, @STREET, @POSTAL_CODE, @CITY, @FLAGS)"; + this.SetParameters(cmd); + } + + public void SetDelete(IDbCommand cmd) + { + cmd.CommandText = "DELETE FROM participant WHERE id = @ID"; + + IDataParameter idParam = cmd.CreateParameter(); + idParam.ParameterName = "ID"; + idParam.Value = this.Id; + cmd.Parameters.Add(idParam); + } + + public static List LoadElems(IDataReader reader) + { + List result = new List(); + while(reader.Read()) + { + Participant p = new(); + p.Id = (uint) reader.GetInt32(0); + if(!reader.IsDBNull(1)) p.Name = reader.GetString(1); + if(!reader.IsDBNull(2)) p.Street = reader.GetString(2); + if (!reader.IsDBNull(3)) p.PostalCode = reader.GetString(3); + if (!reader.IsDBNull(4)) p.City = reader.GetString(4); + if(!reader.IsDBNull(5)) p.Flags = (uint) reader.GetInt32(5); + if (!reader.IsDBNull(6)) p.Created = reader.GetDateTime(6); + if(!reader.IsDBNull(7)) p.Modified = reader.GetDateTime(7); + result.Add(p); + } + return result; + } + + #endregion + + #region private methods + + private void SetParameters(IDbCommand cmd) + { + IDbDataParameter name = cmd.CreateParameter(); + name.ParameterName = "NAME"; + name.Value = this.Name; + cmd.Parameters.Add(name); + + IDbDataParameter street = cmd.CreateParameter(); + street.ParameterName = "STREET"; + street.Value = this.Street; + cmd.Parameters.Add(street); + + IDataParameter postal_code = cmd.CreateParameter(); + postal_code.ParameterName = "POSTAL_CODE"; + postal_code.Value = this.PostalCode; + cmd.Parameters.Add(postal_code); + + IDataParameter city = cmd.CreateParameter(); + city.ParameterName = "CITY"; + city.Value = this.City; + cmd.Parameters.Add(city); + + IDataParameter flags = cmd.CreateParameter(); + flags.ParameterName = "FLAGS"; + flags.Value = this.Flags; + cmd.Parameters.Add(flags); + + IDataParameter idParam = cmd.CreateParameter(); + idParam.ParameterName = "ID"; + idParam.Value = this.Id; + cmd.Parameters.Add(idParam); + } + + #endregion + #region overrides public override string ToString() diff --git a/src/brecal.model/Role.cs b/src/brecal.model/Role.cs index bc182bd..5fa802d 100644 --- a/src/brecal.model/Role.cs +++ b/src/brecal.model/Role.cs @@ -19,6 +19,16 @@ namespace brecal.model #region overrides + public async override void Save(IDBManager manager) + { + + } + + public async override void Delete(IDBManager manager) + { + + } + public override string ToString() { return this.Name ?? $"{base.Id} - {this.GetType().Name}"; diff --git a/src/brecal.model/RoleAssignment.cs b/src/brecal.model/RoleAssignment.cs index 3fd46b5..58ebd60 100644 --- a/src/brecal.model/RoleAssignment.cs +++ b/src/brecal.model/RoleAssignment.cs @@ -17,5 +17,15 @@ namespace brecal.model #endregion + public async override void Save(IDBManager manager) + { + + } + + public async override void Delete(IDBManager manager) + { + + } + } } diff --git a/src/brecal.model/Securable.cs b/src/brecal.model/Securable.cs index 906e8e8..cfb50b8 100644 --- a/src/brecal.model/Securable.cs +++ b/src/brecal.model/Securable.cs @@ -17,6 +17,16 @@ namespace brecal.model #region overrides + public async override void Save(IDBManager manager) + { + + } + + public async override void Delete(IDBManager manager) + { + + } + public override string ToString() { return this.Name ?? $"{base.Id} - {this.GetType().Name}"; diff --git a/src/brecal.model/SecurableAssignment.cs b/src/brecal.model/SecurableAssignment.cs index 7a68bd2..d19a620 100644 --- a/src/brecal.model/SecurableAssignment.cs +++ b/src/brecal.model/SecurableAssignment.cs @@ -15,5 +15,16 @@ namespace brecal.model public Securable? AssignedSecurable { get; set; } #endregion + + public async override void Save(IDBManager manager) + { + + } + + public async override void Delete(IDBManager manager) + { + + } + } } diff --git a/src/brecal.model/User.cs b/src/brecal.model/User.cs index 3358dcb..9eed56f 100644 --- a/src/brecal.model/User.cs +++ b/src/brecal.model/User.cs @@ -18,6 +18,16 @@ #region overrides + public async override void Save(IDBManager manager) + { + + } + + public async override void Delete(IDBManager manager) + { + + } + public override string ToString() { return this.Username ?? $"{base.Id} - {this.GetType().Name}"; diff --git a/src/brecal.mysql/DBManager.cs b/src/brecal.mysql/DBManager.cs index f85f5b9..27c1f69 100644 --- a/src/brecal.mysql/DBManager.cs +++ b/src/brecal.mysql/DBManager.cs @@ -2,35 +2,26 @@ using MySqlConnector; using System.Data; using System.Runtime.CompilerServices; +using static brecal.model.IDBManager; namespace brecal.mysql { public class DBManager : IDBManager { - private static string _connectionString = ""; - + // TODO: remove this and use certificates instead + private static readonly string _connectionString = "Server=localhost;User ID=ds;Password=HalloWach23;Database=bremen_calling"; - public async void Generic() - { - await using var connection = new MySqlConnection("Server=myserver;User ID=mylogin;Password=mypass;Database=mydatabase"); - await connection.OpenAsync(); - - using var command = new MySqlCommand("SELECT field FROM table;", connection); - await using var reader = await command.ExecuteReaderAsync(); - while (await reader.ReadAsync()) - Console.WriteLine(reader.GetString(0)); - } - - public async void Load(Action prepareAction, Action loadAction) + public async Task> Load(Action prepareAction, LoadFunc loadAction) { await using MySqlConnection connection = new MySqlConnection(_connectionString); await connection.OpenAsync(); - using MySqlCommand cmd = new MySqlCommand(); + using MySqlCommand cmd = new(); cmd.Connection = connection; prepareAction(cmd); MySqlDataReader reader = await cmd.ExecuteReaderAsync(); - loadAction(reader); + List result = loadAction(reader); reader.Close(); + return result; } public async Task ExecuteScalar(Action prepareAction) @@ -38,7 +29,7 @@ namespace brecal.mysql await using MySqlConnection connection = new MySqlConnection(_connectionString); await connection.OpenAsync(); - using MySqlCommand cmd = new MySqlCommand(); + using MySqlCommand cmd = new(); cmd.Connection = connection; prepareAction(cmd); object? result = await cmd.ExecuteScalarAsync(); @@ -47,10 +38,10 @@ namespace brecal.mysql public async Task ExecuteNonQuery(Action prepareAction) { - await using MySqlConnection connection = new MySqlConnection(_connectionString); + await using MySqlConnection connection = new(_connectionString); await connection.OpenAsync(); - using MySqlCommand cmd = new MySqlCommand(); + using MySqlCommand cmd = new(); cmd.Connection = connection; prepareAction(cmd); int result = await cmd.ExecuteNonQueryAsync(); From a01b88e0c913d4411b5637b29f05152428ec9214 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 16 Apr 2023 12:59:13 +0200 Subject: [PATCH 06/12] Loading of participant and user functional --- src/RoleEditor/MainWindow.xaml.cs | 53 +++++++++++++--- src/brecal.model/DbEntity.cs | 33 +++++++++- src/brecal.model/IDBManager.cs | 4 +- src/brecal.model/Participant.cs | 80 ++++++++++--------------- src/brecal.model/Role.cs | 77 ++++++++++++++++++++++-- src/brecal.model/RoleAssignment.cs | 12 +++- src/brecal.model/Securable.cs | 12 +++- src/brecal.model/SecurableAssignment.cs | 12 +++- src/brecal.model/User.cs | 61 +++++++++++++++++-- src/brecal.mysql/DBManager.cs | 4 +- 10 files changed, 268 insertions(+), 80 deletions(-) diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs index 2767da5..d2c511a 100644 --- a/src/RoleEditor/MainWindow.xaml.cs +++ b/src/RoleEditor/MainWindow.xaml.cs @@ -33,7 +33,7 @@ namespace RoleEditor private readonly ObservableCollection _users = new ObservableCollection(); private readonly ObservableCollection _assignedRoles = new ObservableCollection(); private readonly ObservableCollection _assignedSecurables = new ObservableCollection(); - private DBManager? _dbManager; + private DBManager _dbManager; #endregion @@ -42,19 +42,29 @@ namespace RoleEditor public MainWindow() { InitializeComponent(); + _dbManager = new(); } - private void Window_Loaded(object sender, RoutedEventArgs e) + private async void Window_Loaded(object sender, RoutedEventArgs e) { // try database connection try - { - _dbManager = new(); - + { // load all participants - + foreach(Participant p in await Participant.LoadAll(_dbManager)) + _participants.Add(p); + this.listBoxParticipant.ItemsSource = _participants; // load all roles + foreach(Role r in await Role.LoadAll(_dbManager)) + _roles.Add(r); + this.listBoxRoles.ItemsSource = _roles; + + // set other item sources + this.listBoxUser.ItemsSource = _users; + this.listBoxSecurables.ItemsSource = _securables; + this.listBoxRoleSecurables.ItemsSource = _assignedSecurables; + this.listBoxUserRoles.ItemsSource = _assignedRoles; } catch (Exception ex) { @@ -111,9 +121,22 @@ namespace RoleEditor #region listbox selection callbacks - private void listBoxParticipant_SelectionChanged(object sender, SelectionChangedEventArgs e) + private async void listBoxParticipant_SelectionChanged(object sender, SelectionChangedEventArgs e) { + Participant? p = this.listBoxParticipant.SelectedItem as Participant; + + this.textBoxParticipantName.Text = (p != null) ? p.Name : string.Empty; + this.textBoxParticipantStreet.Text = (p != null) ? p.Street : string.Empty; + this.textBoxParticipantPostalCode.Text = (p != null) ? p.PostalCode : string.Empty; + this.textBoxParticipantCity.Text = (p != null) ? p.City : string.Empty; + // this.checkboxParticipantActive.Checked = (p != null) ? p. + this.textBoxParticipantCreated.Text = (p != null) ? p.Created.ToString() : string.Empty; + this.textBoxParticipantModified.Text = (p != null) ? p.Modified.ToString() : string.Empty; + // -> load users for this participant selection + this._users.Clear(); + foreach (User u in await User.LoadForParticipant(p, _dbManager)) + _users.Add(u); } private void listBoxRoles_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -123,6 +146,13 @@ namespace RoleEditor private void listBoxUser_SelectionChanged(object sender, SelectionChangedEventArgs e) { + User? u = this.listBoxUser.SelectedItem as User; + this.textBoxUserFirstName.Text = (u != null) ? u.Firstname : string.Empty; + this.textBoxUserLastName.Text = (u != null) ? u.Lastname : string.Empty; + this.textBoxUserUserName.Text = (u != null) ? u.Username : string.Empty; + this.textBoxUserAPIKey.Text = (u != null) ? u.APIKey : string.Empty; + this.textBoxUserCreated.Text = (u != null) ? u.Created.ToString() : string.Empty; + this.textBoxUserModified.Text = (u != null) ? u.Modified.ToString() : string.Empty; } @@ -147,7 +177,14 @@ namespace RoleEditor private void menuItemNewUser_Click(object sender, RoutedEventArgs e) { - + Participant? p = this.listBoxParticipant.SelectedItem as Participant; + if(p != null) + { + User u = new(); + u.Participant_Id = p.Id; + _users.Add(u); + this.listBoxUser.SelectedItem = u; + } } private void menuItemDeleteUser_Click(object sender, RoutedEventArgs e) diff --git a/src/brecal.model/DbEntity.cs b/src/brecal.model/DbEntity.cs index 4a098b8..1b9b57a 100644 --- a/src/brecal.model/DbEntity.cs +++ b/src/brecal.model/DbEntity.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -23,14 +24,42 @@ namespace brecal.model /// public DateTime? Modified { get; set; } + /// + /// Set query and cmd parameters for an update query + /// + /// CMD created by DB manager + public abstract void SetUpdate(IDbCommand cmd); + + /// + /// set query and cmd parameters for a create query + /// + /// CMD created by DB manager + public abstract void SetCreate(IDbCommand cmd); + + /// + /// set query and cmd parameters for a delete query + /// + /// CMD created by DB manager + public abstract void SetDelete(IDbCommand cmd); + /// /// Each database entity must be able to save itself to the database /// - public abstract void Save(IDBManager manager); + public async void Save(IDBManager manager) + { + if (this.Created.HasValue) + await manager.ExecuteNonQuery(this.SetUpdate); + else + await manager.ExecuteNonQuery(this.SetCreate); + } /// /// Each entity must be able to delete itself /// - public abstract void Delete(IDBManager manager); + public async void Delete(IDBManager manager) + { + await manager.ExecuteNonQuery(this.SetDelete); + } + } } diff --git a/src/brecal.model/IDBManager.cs b/src/brecal.model/IDBManager.cs index 15ff592..bcc2814 100644 --- a/src/brecal.model/IDBManager.cs +++ b/src/brecal.model/IDBManager.cs @@ -12,7 +12,9 @@ namespace brecal.model delegate List LoadFunc(T entity); - Task> Load(Action prepareAction, LoadFunc loadAction); + delegate void QueryFunc(IDbCommand cmd, params object[] args); + + Task> Load(QueryFunc prepareAction, LoadFunc loadAction, params object[] args); Task ExecuteScalar(Action prepareAction); diff --git a/src/brecal.model/Participant.cs b/src/brecal.model/Participant.cs index 0e68936..fa5738a 100644 --- a/src/brecal.model/Participant.cs +++ b/src/brecal.model/Participant.cs @@ -21,61 +21,60 @@ namespace brecal.model public uint Flags { get; set; } - #endregion - - #region abstract method implementation - - // TODO: Diese Funktionen in die Basisklasse verschieben und die SetUpdate SetCreate SetDelete - // abstract machen - - public async override void Save(IDBManager manager) - { - if (this.Created.HasValue) - await manager.ExecuteNonQuery(this.SetUpdate); - else - await manager.ExecuteNonQuery(this.SetCreate); - } - - public async override void Delete(IDBManager manager) - { - await manager.ExecuteNonQuery(this.SetDelete); - } - - #endregion + #endregion #region public static methods public static async Task> LoadAll(IDBManager manager) { List loadResultList = await manager.Load(SetLoadQuery, LoadElems); - List result = new List(); + List result = new(); foreach (Participant p in loadResultList.Cast()) result.Add(p); return result; + } + + public static List LoadElems(IDataReader reader) + { + List result = new List(); + while (reader.Read()) + { + Participant p = new(); + p.Id = (uint)reader.GetInt32(0); + if (!reader.IsDBNull(1)) p.Name = reader.GetString(1); + if (!reader.IsDBNull(2)) p.Street = reader.GetString(2); + if (!reader.IsDBNull(3)) p.PostalCode = reader.GetString(3); + if (!reader.IsDBNull(4)) p.City = reader.GetString(4); + if (!reader.IsDBNull(5)) p.Flags = (uint)reader.GetInt32(5); + if (!reader.IsDBNull(6)) p.Created = reader.GetDateTime(6); + if (!reader.IsDBNull(7)) p.Modified = reader.GetDateTime(7); + result.Add(p); + } + return result; } - #endregion - - #region parameter funcs - - public static void SetLoadQuery(IDbCommand cmd) + public static void SetLoadQuery(IDbCommand cmd, params object[] list) { cmd.CommandText = "SELECT id, name, street, postal_code, city, flags, created, modified FROM participant"; } - public void SetUpdate(IDbCommand cmd) + #endregion + + #region abstract method implementation + + public override void SetUpdate(IDbCommand cmd) { cmd.CommandText = "UPDATE participant set name = @NAME, street = @STREET, postal_code = @POSTAL_CODE, city = @CITY, flags = @FLAGS WHERE id = @ID"; this.SetParameters(cmd); } - public void SetCreate(IDbCommand cmd) + public override void SetCreate(IDbCommand cmd) { cmd.CommandText = "INSERT INTO participant (name, street, postal_code, city, flags) VALUES ( @NAME, @STREET, @POSTAL_CODE, @CITY, @FLAGS)"; this.SetParameters(cmd); } - public void SetDelete(IDbCommand cmd) + public override void SetDelete(IDbCommand cmd) { cmd.CommandText = "DELETE FROM participant WHERE id = @ID"; @@ -83,26 +82,7 @@ namespace brecal.model idParam.ParameterName = "ID"; idParam.Value = this.Id; cmd.Parameters.Add(idParam); - } - - public static List LoadElems(IDataReader reader) - { - List result = new List(); - while(reader.Read()) - { - Participant p = new(); - p.Id = (uint) reader.GetInt32(0); - if(!reader.IsDBNull(1)) p.Name = reader.GetString(1); - if(!reader.IsDBNull(2)) p.Street = reader.GetString(2); - if (!reader.IsDBNull(3)) p.PostalCode = reader.GetString(3); - if (!reader.IsDBNull(4)) p.City = reader.GetString(4); - if(!reader.IsDBNull(5)) p.Flags = (uint) reader.GetInt32(5); - if (!reader.IsDBNull(6)) p.Created = reader.GetDateTime(6); - if(!reader.IsDBNull(7)) p.Modified = reader.GetDateTime(7); - result.Add(p); - } - return result; - } + } #endregion diff --git a/src/brecal.model/Role.cs b/src/brecal.model/Role.cs index 5fa802d..b9c67d2 100644 --- a/src/brecal.model/Role.cs +++ b/src/brecal.model/Role.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -17,16 +18,62 @@ namespace brecal.model #endregion - #region overrides + #region public static methods - public async override void Save(IDBManager manager) + public static async Task> LoadAll(IDBManager manager) { - + List loadResultList = await manager.Load(SetLoadQuery, LoadElems); + List result = new(); + foreach (Role r in loadResultList.Cast()) + result.Add(r); + return result; } - public async override void Delete(IDBManager manager) + public static void SetLoadQuery(IDbCommand cmd, params object[] list) { + cmd.CommandText = "SELECT id, name, description, created, modified FROM role"; + } + public static List LoadElems(IDataReader reader) + { + List result = new List(); + while (reader.Read()) + { + Role r = new(); + r.Id = (uint)reader.GetInt32(0); + if (!reader.IsDBNull(1)) r.Name = reader.GetString(1); + if (!reader.IsDBNull(2)) r.Description = reader.GetString(2); + if (!reader.IsDBNull(3)) r.Created = reader.GetDateTime(3); + if (!reader.IsDBNull(4)) r.Modified = reader.GetDateTime(4); + result.Add(r); + } + return result; + } + + #endregion + + #region overrides + + public override void SetUpdate(IDbCommand cmd) + { + cmd.CommandText = "UPDATE role set name = @NAME, description = @DESC WHERE id = @ID"; + this.SetParameters(cmd); + } + + public override void SetCreate(IDbCommand cmd) + { + cmd.CommandText = "INSERT INTO role (name, description) VALUES ( @NAME, @DESC)"; + this.SetParameters(cmd); + } + + public override void SetDelete(IDbCommand cmd) + { + cmd.CommandText = "DELETE FROM role WHERE id = @ID"; + + IDataParameter idParam = cmd.CreateParameter(); + idParam.ParameterName = "ID"; + idParam.Value = this.Id; + cmd.Parameters.Add(idParam); } public override string ToString() @@ -36,5 +83,27 @@ namespace brecal.model #endregion + #region private methods + + private void SetParameters(IDbCommand cmd) + { + IDbDataParameter name = cmd.CreateParameter(); + name.ParameterName = "NAME"; + name.Value = this.Name; + cmd.Parameters.Add(name); + + IDbDataParameter desc = cmd.CreateParameter(); + desc.ParameterName = "DESC"; + desc.Value = this.Description; + cmd.Parameters.Add(desc); + + IDataParameter idParam = cmd.CreateParameter(); + idParam.ParameterName = "ID"; + idParam.Value = this.Id; + cmd.Parameters.Add(idParam); + } + + #endregion + } } diff --git a/src/brecal.model/RoleAssignment.cs b/src/brecal.model/RoleAssignment.cs index 58ebd60..489df60 100644 --- a/src/brecal.model/RoleAssignment.cs +++ b/src/brecal.model/RoleAssignment.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -17,14 +18,19 @@ namespace brecal.model #endregion - public async override void Save(IDBManager manager) + public override void SetUpdate(IDbCommand cmd) { - + throw new NotImplementedException(); } - public async override void Delete(IDBManager manager) + public override void SetCreate(IDbCommand cmd) { + throw new NotImplementedException(); + } + public override void SetDelete(IDbCommand cmd) + { + throw new NotImplementedException(); } } diff --git a/src/brecal.model/Securable.cs b/src/brecal.model/Securable.cs index cfb50b8..f0e6f06 100644 --- a/src/brecal.model/Securable.cs +++ b/src/brecal.model/Securable.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -17,14 +18,19 @@ namespace brecal.model #region overrides - public async override void Save(IDBManager manager) + public override void SetUpdate(IDbCommand cmd) { - + throw new NotImplementedException(); } - public async override void Delete(IDBManager manager) + public override void SetCreate(IDbCommand cmd) { + throw new NotImplementedException(); + } + public override void SetDelete(IDbCommand cmd) + { + throw new NotImplementedException(); } public override string ToString() diff --git a/src/brecal.model/SecurableAssignment.cs b/src/brecal.model/SecurableAssignment.cs index d19a620..5ae9eae 100644 --- a/src/brecal.model/SecurableAssignment.cs +++ b/src/brecal.model/SecurableAssignment.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -16,14 +17,19 @@ namespace brecal.model #endregion - public async override void Save(IDBManager manager) + public override void SetUpdate(IDbCommand cmd) { - + throw new NotImplementedException(); } - public async override void Delete(IDBManager manager) + public override void SetCreate(IDbCommand cmd) { + throw new NotImplementedException(); + } + public override void SetDelete(IDbCommand cmd) + { + throw new NotImplementedException(); } } diff --git a/src/brecal.model/User.cs b/src/brecal.model/User.cs index 9eed56f..38759c8 100644 --- a/src/brecal.model/User.cs +++ b/src/brecal.model/User.cs @@ -1,4 +1,6 @@ -namespace brecal.model +using System.Data; + +namespace brecal.model { public class User : DbEntity { @@ -14,18 +16,67 @@ public string? APIKey { get; set; } + public uint? Participant_Id { get; set; } + + #endregion + + #region public static methods + + public static async Task> LoadForParticipant(Participant? p, IDBManager manager) + { + List loadResultList = await manager.Load(SetLoadQuery, LoadElems, args: p); + List result = new(); + foreach (User u in loadResultList.Cast()) + result.Add(u); + return result; + } + + public static void SetLoadQuery(IDbCommand cmd, params object[] args) + { + cmd.CommandText = "SELECT id, first_name, last_name, user_name, api_key, created, modified FROM user WHERE participant_id = @PID"; + if (args.Length != 1 || !(args[0] is Participant)) + throw new ArgumentException("loader needs single partipant as argument"); + IDataParameter pid = cmd.CreateParameter(); + pid.ParameterName = "PID"; + pid.Value = ((Participant)args[0]).Id; + cmd.Parameters.Add(pid); + } + + public static List LoadElems(IDataReader reader) + { + List result = new List(); + while (reader.Read()) + { + User u = new(); + u.Id = (uint)reader.GetInt32(0); + if (!reader.IsDBNull(1)) u.Firstname = reader.GetString(1); + if (!reader.IsDBNull(2)) u.Lastname = reader.GetString(2); + if (!reader.IsDBNull(3)) u.Username = reader.GetString(3); + if (!reader.IsDBNull(4)) u.APIKey = reader.GetString(4); + if (!reader.IsDBNull(5)) u.Created = reader.GetDateTime(5); + if (!reader.IsDBNull(6)) u.Modified = reader.GetDateTime(6); + result.Add(u); + } + return result; + } + #endregion #region overrides - public async override void Save(IDBManager manager) + public override void SetUpdate(IDbCommand cmd) { - + throw new NotImplementedException(); } - public async override void Delete(IDBManager manager) + public override void SetCreate(IDbCommand cmd) { + throw new NotImplementedException(); + } + public override void SetDelete(IDbCommand cmd) + { + throw new NotImplementedException(); } public override string ToString() @@ -33,6 +84,8 @@ return this.Username ?? $"{base.Id} - {this.GetType().Name}"; } + + #endregion } diff --git a/src/brecal.mysql/DBManager.cs b/src/brecal.mysql/DBManager.cs index 27c1f69..b26c1c2 100644 --- a/src/brecal.mysql/DBManager.cs +++ b/src/brecal.mysql/DBManager.cs @@ -11,13 +11,13 @@ namespace brecal.mysql // TODO: remove this and use certificates instead private static readonly string _connectionString = "Server=localhost;User ID=ds;Password=HalloWach23;Database=bremen_calling"; - public async Task> Load(Action prepareAction, LoadFunc loadAction) + public async Task> Load(QueryFunc prepareAction, LoadFunc loadAction, params object[] args) { await using MySqlConnection connection = new MySqlConnection(_connectionString); await connection.OpenAsync(); using MySqlCommand cmd = new(); cmd.Connection = connection; - prepareAction(cmd); + prepareAction(cmd, args); MySqlDataReader reader = await cmd.ExecuteReaderAsync(); List result = loadAction(reader); reader.Close(); From a86b02d541a3f956ac427cbf0c47d6be687e586c Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 16 Apr 2023 16:32:25 +0200 Subject: [PATCH 07/12] Implemented user create and update --- src/RoleEditor/MainWindow.xaml.cs | 27 ++++++++++++-- src/brecal.model/DbEntity.cs | 6 +++- src/brecal.model/User.cs | 60 ++++++++++++++++++++++++++++--- src/brecal.mysql/DBManager.cs | 3 +- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs index d2c511a..78a73b9 100644 --- a/src/RoleEditor/MainWindow.xaml.cs +++ b/src/RoleEditor/MainWindow.xaml.cs @@ -17,6 +17,9 @@ using System.Windows.Shapes; using System.Collections.ObjectModel; using brecal.model; using brecal.mysql; +using System.Security.Cryptography; +using System.Security.Policy; +using System.Windows.Markup; namespace RoleEditor { @@ -84,7 +87,27 @@ namespace RoleEditor private void buttonUserSave_Click(object sender, RoutedEventArgs e) { - + User? u = this.listBoxUser.SelectedItem as User; + if(u != null) + { + u.Firstname = this.textBoxUserFirstName.Text.Trim(); + u.Lastname = this.textBoxUserLastName.Text.Trim(); + u.Username = this.textBoxUserUserName.Text.Trim(); + if(this.textBoxUserPassword.Text.Trim().Length > 0 ) + { + var data = Encoding.UTF8.GetBytes(this.textBoxUserPassword.Text.Trim()); + using SHA512 sha = SHA512.Create(); + byte[] hashedInputBytes = sha.ComputeHash(data); + var hashedInputStringBuilder = new StringBuilder(128); + foreach (var b in hashedInputBytes) + hashedInputStringBuilder.Append(b.ToString("X2")); + u.PasswordHash = hashedInputStringBuilder.ToString(); + } + u.APIKey = this.textBoxUserAPIKey.Text.Trim(); + u.Save(_dbManager); + this.listBoxUser.ItemsSource = null; + this.listBoxUser.ItemsSource = _users; + } } private void buttonAddRole_Click(object sender, RoutedEventArgs e) @@ -153,7 +176,7 @@ namespace RoleEditor this.textBoxUserAPIKey.Text = (u != null) ? u.APIKey : string.Empty; this.textBoxUserCreated.Text = (u != null) ? u.Created.ToString() : string.Empty; this.textBoxUserModified.Text = (u != null) ? u.Modified.ToString() : string.Empty; - + this.textBoxUserPassword.Text = string.Empty; } private void listBoxSecurables_SelectionChanged(object sender, SelectionChangedEventArgs e) diff --git a/src/brecal.model/DbEntity.cs b/src/brecal.model/DbEntity.cs index 1b9b57a..dd0b778 100644 --- a/src/brecal.model/DbEntity.cs +++ b/src/brecal.model/DbEntity.cs @@ -48,9 +48,13 @@ namespace brecal.model public async void Save(IDBManager manager) { if (this.Created.HasValue) + { await manager.ExecuteNonQuery(this.SetUpdate); + } else - await manager.ExecuteNonQuery(this.SetCreate); + { + this.Id = (uint)await manager.ExecuteNonQuery(this.SetCreate); + } } /// diff --git a/src/brecal.model/User.cs b/src/brecal.model/User.cs index 38759c8..7386457 100644 --- a/src/brecal.model/User.cs +++ b/src/brecal.model/User.cs @@ -66,17 +66,27 @@ namespace brecal.model public override void SetUpdate(IDbCommand cmd) { - throw new NotImplementedException(); + if(!string.IsNullOrEmpty(this.PasswordHash)) + cmd.CommandText = "UPDATE user SET first_name = @FIRSTNAME, last_name = @LASTNAME, user_name = @USERNAME, password_hash = @PWHASH, api_key = @APIKEY WHERE id = @ID"; + else + cmd.CommandText = "UPDATE user SET first_name = @FIRSTNAME, last_name = @LASTNAME, user_name = @USERNAME, api_key = @APIKEY WHERE id = @ID"; + this.SetParameters(cmd); } public override void SetCreate(IDbCommand cmd) - { - throw new NotImplementedException(); + { + cmd.CommandText = "INSERT INTO user (participant_id, first_name, last_name, user_name, password_hash, api_key) VALUES ( @PID, @FIRSTNAME, @LASTNAME, @USERNAME, @PWHASH, @APIKEY)"; + this.SetParameters(cmd); } public override void SetDelete(IDbCommand cmd) { - throw new NotImplementedException(); + cmd.CommandText = "DELETE FROM user WHERE id = @ID"; + + IDataParameter idParam = cmd.CreateParameter(); + idParam.ParameterName = "ID"; + idParam.Value = this.Id; + cmd.Parameters.Add(idParam); } public override string ToString() @@ -84,7 +94,47 @@ namespace brecal.model return this.Username ?? $"{base.Id} - {this.GetType().Name}"; } - + #endregion + + #region private methods + + private void SetParameters(IDbCommand cmd) + { + IDbDataParameter id = cmd.CreateParameter(); + id.ParameterName = "ID"; + id.Value = this.Id; + cmd.Parameters.Add(id); + + IDbDataParameter pid = cmd.CreateParameter(); + pid.ParameterName = "PID"; + pid.Value = this.Participant_Id; + cmd.Parameters.Add(pid); + + IDbDataParameter firstname = cmd.CreateParameter(); + firstname.ParameterName = "FIRSTNAME"; + firstname.Value = this.Firstname; + cmd.Parameters.Add(firstname); + + IDbDataParameter lastname = cmd.CreateParameter(); + lastname.ParameterName = "LASTNAME"; + lastname.Value = this.Lastname; + cmd.Parameters.Add(lastname); + + IDbDataParameter username = cmd.CreateParameter(); + username.ParameterName = "USERNAME"; + username.Value = this.Username; + cmd.Parameters.Add(username); + + IDbDataParameter pwhash = cmd.CreateParameter(); + pwhash.ParameterName = "PWHASH"; + pwhash.Value = this.PasswordHash; + cmd.Parameters.Add(pwhash); + + IDbDataParameter apikey = cmd.CreateParameter(); + apikey.ParameterName = "APIKEY"; + apikey.Value = this.APIKey; + cmd.Parameters.Add(apikey); + } #endregion diff --git a/src/brecal.mysql/DBManager.cs b/src/brecal.mysql/DBManager.cs index b26c1c2..0e6972d 100644 --- a/src/brecal.mysql/DBManager.cs +++ b/src/brecal.mysql/DBManager.cs @@ -44,7 +44,8 @@ namespace brecal.mysql using MySqlCommand cmd = new(); cmd.Connection = connection; prepareAction(cmd); - int result = await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(); + int result = (int)cmd.LastInsertedId; return result; } From 66b2691c415d9b0261add076c8e02c268229f6f5 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 16 Apr 2023 16:58:32 +0200 Subject: [PATCH 08/12] some more UI logic --- src/RoleEditor/MainWindow.xaml.cs | 54 ++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs index 78a73b9..aecf5a7 100644 --- a/src/RoleEditor/MainWindow.xaml.cs +++ b/src/RoleEditor/MainWindow.xaml.cs @@ -82,7 +82,18 @@ namespace RoleEditor private void buttonParticipantSave_Click(object sender, RoutedEventArgs e) { - + Participant? p = this.listBoxParticipant.SelectedItem as Participant; + if (p != null) + { + p.Name = this.textBoxParticipantName.Text.Trim(); + p.Street = this.textBoxParticipantStreet.Text.Trim(); + p.PostalCode = this.textBoxParticipantPostalCode.Text.Trim(); + p.City = this.textBoxParticipantCity.Text.Trim(); + p.Save(_dbManager); + this.listBoxParticipant.ItemsSource = null; + this.listBoxParticipant.ItemsSource = _users; + this.listBoxParticipant.SelectedItem = p; + } } private void buttonUserSave_Click(object sender, RoutedEventArgs e) @@ -107,6 +118,7 @@ namespace RoleEditor u.Save(_dbManager); this.listBoxUser.ItemsSource = null; this.listBoxUser.ItemsSource = _users; + this.listBoxUser.SelectedItem = u; } } @@ -132,12 +144,29 @@ namespace RoleEditor private void buttonSaveSecurable_Click(object sender, RoutedEventArgs e) { - + Securable? s = this.listBoxSecurables.SelectedItem as Securable; + if(s != null) + { + s.Name = this.textBoxSecurableName.Text.Trim(); + s.Save(_dbManager); + this.listBoxSecurables.ItemsSource = null; + this.listBoxSecurables.ItemsSource = _securables; + this.listBoxSecurables.SelectedItem = s; + } } private void buttonSaveRole_Click(object sender, RoutedEventArgs e) { - + Role? r = this.listBoxRoles.SelectedItem as Role; + if(r != null) + { + r.Name = this.textBoxRoleName.Text.Trim(); + r.Description = this.textBoxRoleDescription.Text.Trim(); + r.Save(_dbManager); + this.listBoxRoles.ItemsSource = null; + this.listBoxRoles.ItemsSource = _roles; + this.listBoxRoles.SelectedItem = r; + } } #endregion @@ -164,7 +193,9 @@ namespace RoleEditor private void listBoxRoles_SelectionChanged(object sender, SelectionChangedEventArgs e) { - + Role? r = this.listBoxRoles.SelectedItem as Role; + this.textBoxRoleName.Text = (r != null) ? r.Name : string.Empty; + this.textBoxRoleDescription.Text = (r != null) ? r.Description : string.Empty; } private void listBoxUser_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -181,7 +212,8 @@ namespace RoleEditor private void listBoxSecurables_SelectionChanged(object sender, SelectionChangedEventArgs e) { - + Securable? s = this.listBoxSecurables.SelectedItem as Securable; + this.textBoxSecurableName.Text = (s != null) ? s.Name : string.Empty; } #endregion @@ -195,7 +227,9 @@ namespace RoleEditor private void menuItemNewParticipant_Click(object sender, RoutedEventArgs e) { - + Participant p = new(); + this._participants.Add(p); + this.listBoxParticipant.SelectedItem = p; } private void menuItemNewUser_Click(object sender, RoutedEventArgs e) @@ -217,7 +251,9 @@ namespace RoleEditor private void menuItemNewRole_Click(object sender, RoutedEventArgs e) { - + Role r = new(); + this._roles.Add(r); + this.listBoxRoles.SelectedItem = r; } private void menuItemDeleteRole_Click(object sender, RoutedEventArgs e) @@ -227,7 +263,9 @@ namespace RoleEditor private void menuItemNewSecurable_Click(object sender, RoutedEventArgs e) { - + Securable s = new Securable(); + _securables.Add(s); + this.listBoxSecurables.SelectedItem = s; } private void menuItemDeleteSecurable_Click(object sender, RoutedEventArgs e) From c9aa4397124e64c91fd5551d72787280c0f0f5b2 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 17 Apr 2023 07:49:27 +0200 Subject: [PATCH 09/12] saving securables, more logic --- misc/create_schema.sql | 3 +- src/RoleEditor/MainWindow.xaml | 6 ++-- src/RoleEditor/MainWindow.xaml.cs | 8 +++-- src/brecal.model/Securable.cs | 59 +++++++++++++++++++++++++++++-- src/brecal.mysql/DBManager.cs | 2 +- 5 files changed, 67 insertions(+), 11 deletions(-) diff --git a/misc/create_schema.sql b/misc/create_schema.sql index 7bf326f..e8e7676 100644 --- a/misc/create_schema.sql +++ b/misc/create_schema.sql @@ -101,7 +101,6 @@ CREATE TABLE `participant` ( `street` VARCHAR(128) NULL DEFAULT NULL, `postal_code` VARCHAR(5) NULL DEFAULT NULL, `city` VARCHAR(64) NULL DEFAULT NULL, - `roles` INT(10) UNSIGNED NULL DEFAULT 0 COMMENT 'Bitarray of assigned roles', `flags` INT(10) UNSIGNED NULL DEFAULT NULL, `created` DATETIME NULL DEFAULT current_timestamp(), `modified` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(), @@ -187,7 +186,7 @@ ENGINE=InnoDB CREATE TABLE `securable` ( - `id` INT(10) UNSIGNED NOT NULL, + `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL DEFAULT '', `created` DATETIME NULL DEFAULT current_timestamp(), `modified` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(), diff --git a/src/RoleEditor/MainWindow.xaml b/src/RoleEditor/MainWindow.xaml index 8d24419..a8662ba 100644 --- a/src/RoleEditor/MainWindow.xaml +++ b/src/RoleEditor/MainWindow.xaml @@ -174,8 +174,8 @@