Merge branch 'feature/role_editor' into develop

This commit is contained in:
Daniel Schick 2023-04-23 12:51:23 +02:00
commit 9a8c16ad79
34 changed files with 2003 additions and 4 deletions

View File

@ -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(),
@ -175,6 +174,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`)
)
@ -185,8 +186,10 @@ 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(),
PRIMARY KEY (`id`),
UNIQUE INDEX `name` (`name`)
)
@ -199,6 +202,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`),
@ -211,9 +216,11 @@ ENGINE=InnoDB
;
CREATE TABLE `role_securable_map` (
`id` INT(10) UNSIGNED NOT NULL,
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`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`),

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

9
src/RoleEditor/App.xaml Normal file
View File

@ -0,0 +1,9 @@
<Application x:Class="RoleEditor.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RoleEditor"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@ -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
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -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)
)]

View File

@ -0,0 +1,238 @@
<Window x:Class="RoleEditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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" Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=".5*" />
<RowDefinition Height=".5*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*" />
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<GroupBox Header="Participant" Margin="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width=".38*" />
<ColumnDefinition Width=".62*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="listBoxParticipant" Margin="2" Grid.RowSpan="7" SelectionChanged="listBoxParticipant_SelectionChanged">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuItemNewParticipant" Header="New.." Click="menuItemNewParticipant_Click">
<MenuItem.Icon>
<Image Source="Resources/add.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="menuItemDeleteParticipant" Header="Delete" Click="menuItemDeleteParticipant_Click">
<MenuItem.Icon>
<Image Source="Resources/delete2.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Label Content="Name" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="Street" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="Postal code" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="City" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="Active" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="Created" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="Modified" Grid.Row="6" Grid.Column="1" HorizontalAlignment="Right"/>
<TextBox x:Name="textBoxParticipantName" Grid.Row="0" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxParticipantStreet" Grid.Row="1" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxParticipantPostalCode" Grid.Row="2" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxParticipantCity" Grid.Row="3" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<CheckBox x:Name="checkboxParticipantActive" Grid.Row="4" Grid.Column="2" VerticalAlignment="Center" />
<TextBox x:Name="textBoxParticipantCreated" Grid.Row="5" IsReadOnly="True" IsEnabled="False" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxParticipantModified" Grid.Row="6" IsReadOnly="True" IsEnabled="False" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<Button x:Name="buttonParticipantSave" Grid.Row="7" Grid.Column="2" Click="buttonParticipantSave_Click" Margin="2">
<DockPanel>
<Image Source="./Resources/disk_blue.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="16"/>
<TextBlock Text="Save" VerticalAlignment="Center" DockPanel.Dock="Right"/>
</DockPanel>
</Button>
</Grid>
</GroupBox>
<GroupBox Header="User" Margin="2" Grid.Row="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width=".38*" />
<ColumnDefinition Width=".62*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="listBoxUser" Margin="2" Grid.RowSpan="9" SelectionChanged="listBoxUser_SelectionChanged">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuItemNewUser" Header="New.." Click="menuItemNewUser_Click">
<MenuItem.Icon>
<Image Source="Resources/add.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="menuItemDeleteUser" Header="Delete" Click="menuItemDeleteUser_Click">
<MenuItem.Icon>
<Image Source="Resources/delete2.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Label Grid.Row="0" Grid.Column="1" Content="First name" HorizontalAlignment="Right"/>
<Label Grid.Row="1" Grid.Column="1" Content="Last name" HorizontalAlignment="Right"/>
<Label Grid.Row="2" Grid.Column="1" Content="User name" HorizontalAlignment="Right"/>
<Label Grid.Row="3" Grid.Column="1" Content="Password" HorizontalAlignment="Right"/>
<Label Grid.Row="4" Grid.Column="1" Content="API Key" HorizontalAlignment="Right"/>
<Label Content="Created" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Right"/>
<Label Content="Modified" Grid.Row="6" Grid.Column="1" HorizontalAlignment="Right"/>
<TextBox x:Name="textBoxUserFirstName" Grid.Row="0" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxUserLastName" Grid.Row="1" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxUserUserName" Grid.Row="2" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxUserPassword" Grid.Row="3" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxUserAPIKey" Grid.Row="4" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxUserCreated" Grid.Row="5" IsReadOnly="True" IsEnabled="False" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<TextBox x:Name="textBoxUserModified" Grid.Row="6" IsReadOnly="True" IsEnabled="False" Grid.Column="2" Margin="2" VerticalContentAlignment="Center" />
<Button x:Name="buttonUserSave" Grid.Row="7" Grid.Column="2" Click="buttonUserSave_Click" Margin="2">
<DockPanel>
<Image Source="./Resources/disk_blue.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="16"/>
<TextBlock Text="Save" VerticalAlignment="Center" DockPanel.Dock="Right"/>
</DockPanel>
</Button>
</Grid>
</GroupBox>
<GroupBox Header="Role" Margin="2" Grid.Column="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="*"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<Label Content="User roles" Grid.Row="0" Grid.Column="0" />
<Label Content="All roles" Grid.Row="0" Grid.Column="2" />
<ListBox x:Name="listBoxUserRoles" Grid.Row="1" Grid.Column="0" Grid.RowSpan="3" Margin="2" />
<ListBox x:Name="listBoxRoles" Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" Margin="2" SelectionChanged="listBoxRoles_SelectionChanged">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuItemNewRole" Header="New.." Click="menuItemNewRole_Click">
<MenuItem.Icon>
<Image Source="Resources/add.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="menuItemDeleteRole" Header="Delete" Click="menuItemDeleteRole_Click">
<MenuItem.Icon>
<Image Source="Resources/delete2.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Button x:Name="buttonAddRole" Margin="2" Grid.Row="1" Grid.Column="1" Click="buttonAddRole_Click">
<Image Source="./Resources/arrow_left_green.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="22"/>
</Button>
<Button x:Name="buttonRemoveRole" Margin="2" Grid.Row="2" Grid.Column="1" Click="buttonRemoveRole_Click">
<Image Source="./Resources/delete2.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="22"/>
</Button>
<Label Content="Name" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" />
<Label Content="Descr." Grid.Row="5" Grid.Column="1" HorizontalAlignment="Right" />
<TextBox x:Name="textBoxRoleName" Grid.Row="4" Grid.Column="2" Margin="2" VerticalContentAlignment="Center"/>
<TextBox x:Name="textBoxRoleDescription" Grid.Row="5" Grid.Column="2" Grid.RowSpan="2" Margin="2" VerticalContentAlignment="Top"/>
<Button x:Name="buttonSaveRole" Grid.Row="7" Grid.Column="2" Margin="2" Click="buttonSaveRole_Click">
<DockPanel>
<Image Source="./Resources/disk_blue.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="16"/>
<TextBlock Text="Save" VerticalAlignment="Center" DockPanel.Dock="Right"/>
</DockPanel>
</Button>
</Grid>
</GroupBox>
<GroupBox Header="Securable" Margin="2" Grid.Row="1" Grid.Column="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
<RowDefinition Height="*"/>
<RowDefinition Height="28"/>
<RowDefinition Height="28"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Role securables" />
<Label Grid.Row="0" Grid.Column="2" Content="Securables" />
<ListBox x:Name="listBoxRoleSecurables" Grid.Row="1" Grid.Column="0" Grid.RowSpan="3" Margin="2" />
<ListBox x:Name="listBoxSecurables" Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" Margin="2" SelectionChanged="listBoxSecurables_SelectionChanged">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuItemNewSecurable" Header="New.." Click="menuItemNewSecurable_Click">
<MenuItem.Icon>
<Image Source="Resources/add.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="menuItemDeleteSecurable" Header="Delete" Click="menuItemDeleteSecurable_Click">
<MenuItem.Icon>
<Image Source="Resources/delete2.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Button x:Name="buttonAddSecurable" Margin="2" Grid.Row="1" Grid.Column="1" Click="buttonAddSecurable_Click">
<Image Source="./Resources/arrow_left_green.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="22"/>
</Button>
<Button x:Name="buttonRemoveSecurable" Margin="2" Grid.Row="2" Grid.Column="1" Click="buttonRemoveSecurable_Click">
<Image Source="./Resources/delete2.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="22"/>
</Button>
<Label Content="Name" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" />
<TextBox x:Name="textBoxSecurableName" Grid.Row="4" Grid.Column="2" Margin="2" VerticalContentAlignment="Center"/>
<Button x:Name="buttonSaveSecurable" Grid.Row="5" Grid.Column="2" Margin="2" Click="buttonSaveSecurable_Click">
<DockPanel>
<Image Source="./Resources/disk_blue.png" Margin="0,0,5,0" Height="24" DockPanel.Dock="Left" Width="16"/>
<TextBlock Text="Save" VerticalAlignment="Center" DockPanel.Dock="Right"/>
</DockPanel>
</Button>
</Grid>
</GroupBox>
</Grid>
</Window>

View File

@ -0,0 +1,413 @@

using System;
using System.Collections.ObjectModel;
using System.Security.Cryptography;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using brecal.model;
using brecal.mysql;
namespace RoleEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region private fields
private readonly ObservableCollection<Participant> _participants = new ObservableCollection<Participant>();
private readonly ObservableCollection<Role> _roles = new ObservableCollection<Role>();
private readonly ObservableCollection<Securable> _securables = new ObservableCollection<Securable>();
private readonly ObservableCollection<User> _users = new ObservableCollection<User>();
private readonly ObservableCollection<RoleAssignment> _assignedRoles = new ObservableCollection<RoleAssignment>();
private readonly ObservableCollection<SecurableAssignment> _assignedSecurables = new ObservableCollection<SecurableAssignment>();
private DBManager _dbManager;
#endregion
#region Construction / Loading
public MainWindow()
{
InitializeComponent();
_dbManager = new();
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
// try database connection
try
{
// 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;
// load all securables
foreach(Securable s in await Securable.LoadAll(_dbManager))
_securables.Add(s);
this.listBoxSecurables.ItemsSource = _securables;
// set other item sources (filled later after selection)
this.listBoxUser.ItemsSource = _users;
this.listBoxRoleSecurables.ItemsSource = _assignedSecurables;
this.listBoxUserRoles.ItemsSource = _assignedRoles;
}
catch (Exception ex)
{
MessageBox.Show($"Database connection couldn't be established: {ex.Message}");
this.Close();
}
}
#endregion
#region button callbacks
private async 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();
await p.Save(_dbManager);
this.listBoxParticipant.ItemsSource = null;
this.listBoxParticipant.ItemsSource = _users;
this.listBoxParticipant.SelectedItem = p;
}
}
private async 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();
await u.Save(_dbManager);
this.listBoxUser.ItemsSource = null;
this.listBoxUser.ItemsSource = _users;
this.listBoxUser.SelectedItem = u;
}
}
private async void buttonAddRole_Click(object sender, RoutedEventArgs e)
{
Role? r = this.listBoxRoles.SelectedItem as Role;
User? u = this.listBoxUser.SelectedItem as User;
if((r != null) && (u != null))
{
// test if assignment is already present
bool foundMatchingAssignment = false;
foreach(RoleAssignment ra in _assignedRoles)
{
if((ra.UserId == u.Id) && (ra.RoleId == r.Id))
{
foundMatchingAssignment = true;
break;
}
}
if(!foundMatchingAssignment)
{
RoleAssignment ra = new RoleAssignment();
ra.UserId = (int) u.Id;
ra.RoleId = (int) r.Id;
ra.AssignedRole = r;
ra.AssignedUser = u;
await ra.Save(_dbManager);
_assignedRoles.Add(ra);
}
}
}
private async void buttonRemoveRole_Click(object sender, RoutedEventArgs e)
{
// remove role from user
RoleAssignment? ra = this.listBoxUserRoles.SelectedItem as RoleAssignment;
if(ra != null)
{
await ra.Delete(_dbManager);
if(_assignedRoles.Contains(ra))
_assignedRoles.Remove(ra);
}
}
private async void buttonAddSecurable_Click(object sender, RoutedEventArgs e)
{
if ((this.listBoxRoles.SelectedItem is Role r) && (this.listBoxSecurables.SelectedItem is Securable s))
{
// test if assignment is already present
bool foundMatchingAssignment = false;
foreach (SecurableAssignment sa in _assignedSecurables)
{
if ((sa.SecurableId == s.Id) && (sa.RoleId == r.Id))
{
foundMatchingAssignment = true;
break;
}
}
if (!foundMatchingAssignment)
{
SecurableAssignment sa = new SecurableAssignment();
sa.SecurableId = (int)s.Id;
sa.RoleId = (int)r.Id;
sa.AssignedRole = r;
sa.AssignedSecurable = s;
await sa.Save(_dbManager);
_assignedSecurables.Add(sa);
}
}
}
private async void buttonRemoveSecurable_Click(object sender, RoutedEventArgs e)
{
SecurableAssignment? sa = this.listBoxRoleSecurables.SelectedItem as SecurableAssignment;
if(sa != null)
{
await sa.Delete(_dbManager);
if (_assignedSecurables.Contains(sa))
_assignedSecurables.Remove(sa);
}
}
private async void buttonSaveSecurable_Click(object sender, RoutedEventArgs e)
{
Securable? s = this.listBoxSecurables.SelectedItem as Securable;
if(s != null)
{
s.Name = this.textBoxSecurableName.Text.Trim();
await s.Save(_dbManager);
this.listBoxSecurables.ItemsSource = null;
this.listBoxSecurables.ItemsSource = _securables;
this.listBoxSecurables.SelectedItem = s;
}
}
private async 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();
await r.Save(_dbManager);
this.listBoxRoles.ItemsSource = null;
this.listBoxRoles.ItemsSource = _roles;
this.listBoxRoles.SelectedItem = r;
}
}
#endregion
#region listbox selection callbacks
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 async 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;
_assignedSecurables.Clear();
if (r != null)
{
// load assigned securables
foreach (SecurableAssignment sa in await SecurableAssignment.LoadForRole(r, _dbManager))
{
foreach (Securable s in this._securables)
{
if (sa.SecurableId == s.Id)
{
sa.AssignedSecurable = s;
break;
}
}
_assignedSecurables.Add(sa);
}
}
}
private async 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;
this.textBoxUserPassword.Text = string.Empty;
_assignedRoles.Clear();
if (u != null)
{
// load roles assigned to user
foreach (RoleAssignment ra in await RoleAssignment.LoadForUser(u, _dbManager))
{
foreach (Role r in this._roles)
{
if (ra.RoleId == r.Id)
{
ra.AssignedRole = r;
break;
}
}
_assignedRoles.Add(ra);
}
}
}
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
#region menuitem callbacks
private async void menuItemDeleteParticipant_Click(object sender, RoutedEventArgs e)
{
try
{
if(this.listBoxParticipant.SelectedItem is Participant p)
{
await p.Delete(_dbManager);
this._participants.Remove(p);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
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)
{
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 async void menuItemDeleteUser_Click(object sender, RoutedEventArgs e)
{
try
{
if (this.listBoxUser.SelectedItem is User u)
{
await u.Delete(_dbManager);
this._users.Remove(u);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void menuItemNewRole_Click(object sender, RoutedEventArgs e)
{
Role r = new();
this._roles.Add(r);
this.listBoxRoles.SelectedItem = r;
}
private async void menuItemDeleteRole_Click(object sender, RoutedEventArgs e)
{
try
{
if (this.listBoxRoles.SelectedItem is Role r)
{
await r.Delete(_dbManager);
this._roles.Remove(r);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void menuItemNewSecurable_Click(object sender, RoutedEventArgs e)
{
Securable s = new Securable();
_securables.Add(s);
this.listBoxSecurables.SelectedItem = s;
}
private async void menuItemDeleteSecurable_Click(object sender, RoutedEventArgs e)
{
try
{
if (this.listBoxSecurables.SelectedItem is Securable s)
{
await s.Delete(_dbManager);
this._securables.Remove(s);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
#endregion
}
}

173
src/RoleEditor/Resources.Designer.cs generated Normal file
View File

@ -0,0 +1,173 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RoleEditor {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RoleEditor.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] about {
get {
object obj = ResourceManager.GetObject("about", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] add {
get {
object obj = ResourceManager.GetObject("add", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] arrow_left_green {
get {
object obj = ResourceManager.GetObject("arrow_left_green", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] businessman {
get {
object obj = ResourceManager.GetObject("businessman", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] delete2 {
get {
object obj = ResourceManager.GetObject("delete2", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] disk_blue {
get {
object obj = ResourceManager.GetObject("disk_blue", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] id_card {
get {
object obj = ResourceManager.GetObject("id_card", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] key1 {
get {
object obj = ResourceManager.GetObject("key1", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] key1_add {
get {
object obj = ResourceManager.GetObject("key1_add", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] lock_preferences {
get {
object obj = ResourceManager.GetObject("lock_preferences", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] safe {
get {
object obj = ResourceManager.GetObject("safe", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
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.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="about" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\about.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="add" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\add.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="arrow_left_green" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\arrow_left_green.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="businessman" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\businessman.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="delete2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\delete2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="disk_blue" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\disk_blue.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="id_card" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\id_card.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="key1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\key1.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="key1_add" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\key1_add.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="lock_preferences" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\lock_preferences.ico;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="safe" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\safe.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,61 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<ApplicationIcon>Resources\lock_preferences.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\about.png" />
<None Remove="Resources\add.png" />
<None Remove="Resources\arrow_left_green.png" />
<None Remove="Resources\businessman.png" />
<None Remove="Resources\delete2.png" />
<None Remove="Resources\disk_blue.png" />
<None Remove="Resources\id_card.png" />
<None Remove="Resources\key1.png" />
<None Remove="Resources\key1_add.png" />
<None Remove="Resources\safe.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\brecal.model\brecal.model.csproj" />
<ProjectReference Include="..\brecal.mysql\brecal.mysql.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources/lock_preferences.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\about.png" />
<Resource Include="Resources\add.png" />
<Resource Include="Resources\arrow_left_green.png" />
<Resource Include="Resources\businessman.png" />
<Resource Include="Resources\delete2.png" />
<Resource Include="Resources\disk_blue.png" />
<Resource Include="Resources\id_card.png" />
<Resource Include="Resources\key1.png" />
<Resource Include="Resources\key1_add.png" />
<Resource Include="Resources\safe.png" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1
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
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8A8CB0D3-7728-468E-AB11-E811BA5B5BC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {12E46C08-C5A8-46E8-8A8C-04BA6F197DCB}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace brecal.model
{
public abstract class DbEntity
{
/// <summary>
/// DB primary key
/// </summary>
public uint Id { get; set; }
/// <summary>
/// Creation timestamp, if null record is unsaved
/// </summary>
public DateTime? Created { get; set; }
/// <summary>
/// Modified timestamp, if null record was never modified
/// </summary>
public DateTime? Modified { get; set; }
/// <summary>
/// Set query and cmd parameters for an update query
/// </summary>
/// <param name="cmd">CMD created by DB manager</param>
public abstract void SetUpdate(IDbCommand cmd);
/// <summary>
/// set query and cmd parameters for a create query
/// </summary>
/// <param name="cmd">CMD created by DB manager</param>
public abstract void SetCreate(IDbCommand cmd);
/// <summary>
/// set query and cmd parameters for a delete query
/// </summary>
/// <param name="cmd">CMD created by DB manager</param>
public abstract void SetDelete(IDbCommand cmd);
/// <summary>
/// Each database entity must be able to save itself to the database
/// </summary>
public async Task Save(IDBManager manager)
{
if (this.Created.HasValue)
{
await manager.ExecuteNonQuery(this.SetUpdate);
}
else
{
this.Id = (uint)await manager.ExecuteNonQuery(this.SetCreate);
}
}
/// <summary>
/// Each entity must be able to delete itself
/// </summary>
public async Task Delete(IDBManager manager)
{
await manager.ExecuteNonQuery(this.SetDelete);
}
}
}

View File

@ -0,0 +1,24 @@
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
{
delegate List<DbEntity> LoadFunc<T>(T entity);
delegate void QueryFunc(IDbCommand cmd, params object?[] args);
Task<List<DbEntity>> Load(QueryFunc prepareAction, LoadFunc<IDataReader> loadAction, params object?[] args);
Task<object?> ExecuteScalar(Action<IDbCommand> prepareAction);
Task<int> ExecuteNonQuery(Action<IDbCommand> prepareAction);
}
}

View File

@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Data;
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 public static methods
public static async Task<List<Participant>> LoadAll(IDBManager manager)
{
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems);
List<Participant> result = new();
foreach (Participant p in loadResultList.Cast<Participant>())
result.Add(p);
return result;
}
public static List<DbEntity> LoadElems(IDataReader reader)
{
List<DbEntity> result = new List<DbEntity>();
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;
}
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
{
cmd.CommandText = "SELECT id, name, street, postal_code, city, flags, created, modified FROM participant";
}
#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 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 override 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);
}
#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()
{
return this.Name ?? $"{base.Id} - {this.GetType().Name}";
}
#endregion
}
}

109
src/brecal.model/Role.cs Normal file
View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Data;
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 public static methods
public static async Task<List<Role>> LoadAll(IDBManager manager)
{
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems);
List<Role> result = new();
foreach (Role r in loadResultList.Cast<Role>())
result.Add(r);
return result;
}
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
{
cmd.CommandText = "SELECT id, name, description, created, modified FROM role";
}
public static List<DbEntity> LoadElems(IDataReader reader)
{
List<DbEntity> result = new List<DbEntity>();
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()
{
return this.Name ?? $"{base.Id} - {this.GetType().Name}";
}
#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
}
}

View File

@ -0,0 +1,110 @@
using System.Data;
namespace brecal.model
{
public class RoleAssignment : DbEntity
{
#region Properties
public int? UserId { get; set; }
public int? RoleId { get; set; }
public Role? AssignedRole { get; set; }
public User? AssignedUser { get; set; }
#endregion
#region public static methods
public static async Task<List<RoleAssignment>> LoadForUser(User? u, IDBManager manager)
{
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems, args: u);
List<RoleAssignment> result = new();
foreach (RoleAssignment ra in loadResultList.Cast<RoleAssignment>())
{
ra.AssignedUser = u;
result.Add(ra);
}
return result;
}
public static void SetLoadQuery(IDbCommand cmd, params object?[] args)
{
cmd.CommandText = "SELECT id, user_id, role_id FROM user_role_map WHERE user_id = @UID";
if (args.Length != 1 || !(args[0] is User))
throw new ArgumentException("loader needs single user as argument");
IDataParameter uid = cmd.CreateParameter();
uid.ParameterName = "UID";
if (args[0] is User u)
uid.Value = u.Id;
cmd.Parameters.Add(uid);
}
public static List<DbEntity> LoadElems(IDataReader reader)
{
List<DbEntity> result = new List<DbEntity>();
while (reader.Read())
{
RoleAssignment ra = new();
ra.Id = (uint)reader.GetInt32(0);
if (!reader.IsDBNull(1)) ra.UserId = reader.GetInt32(1);
if (!reader.IsDBNull(2)) ra.RoleId = reader.GetInt32(2);
result.Add(ra);
}
return result;
}
#endregion
#region overrides
public override void SetUpdate(IDbCommand cmd)
{
throw new NotImplementedException();
}
public override void SetCreate(IDbCommand cmd)
{
cmd.CommandText = "INSERT INTO user_role_map (user_id, role_id) VALUES (@USERID, @ROLEID)";
IDbDataParameter userid = cmd.CreateParameter();
userid.ParameterName = "USERID";
userid.Value = this.UserId;
cmd.Parameters.Add(userid);
IDbDataParameter roleid = cmd.CreateParameter();
roleid.ParameterName = "ROLEID";
roleid.Value = this.RoleId;
cmd.Parameters.Add(roleid);
}
public override void SetDelete(IDbCommand cmd)
{
cmd.CommandText = "DELETE FROM user_role_map WHERE id = @ID";
IDataParameter idParam = cmd.CreateParameter();
idParam.ParameterName = "ID";
idParam.Value = this.Id;
cmd.Parameters.Add(idParam);
}
public override string ToString()
{
if (this.AssignedRole == null)
{
return $"{Id}: <defunct role>";
}
else
{
return AssignedRole.Name ?? AssignedRole.Id.ToString();
}
}
#endregion
}
}

View File

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Data;
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 public static methods
public static async Task<List<Securable>> LoadAll(IDBManager manager)
{
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems);
List<Securable> result = new();
foreach (Securable s in loadResultList.Cast<Securable>())
result.Add(s);
return result;
}
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
{
cmd.CommandText = "SELECT id, name, created, modified FROM securable";
}
public static List<DbEntity> LoadElems(IDataReader reader)
{
List<DbEntity> result = new List<DbEntity>();
while (reader.Read())
{
Securable s = new();
s.Id = (uint)reader.GetInt32(0);
if (!reader.IsDBNull(1)) s.Name = reader.GetString(1);
if (!reader.IsDBNull(2)) s.Created = reader.GetDateTime(2);
if (!reader.IsDBNull(3)) s.Modified = reader.GetDateTime(3);
result.Add(s);
}
return result;
}
#endregion
#region overrides
public override void SetUpdate(IDbCommand cmd)
{
cmd.CommandText = "UPDATE securable set name = @NAME WHERE id = @ID";
this.SetParameters(cmd);
}
public override void SetCreate(IDbCommand cmd)
{
cmd.CommandText = "INSERT INTO securable (name) VALUES ( @NAME)";
this.SetParameters(cmd);
}
public override void SetDelete(IDbCommand cmd)
{
cmd.CommandText = "DELETE FROM securable WHERE id = @ID";
this.SetParameters(cmd);
}
public override string ToString()
{
return this.Name ?? $"{base.Id} - {this.GetType().Name}";
}
#endregion
#region private methods
private void SetParameters(IDbCommand cmd)
{
IDbDataParameter name = cmd.CreateParameter();
name.ParameterName = "NAME";
name.Value = this.Name;
cmd.Parameters.Add(name);
IDataParameter idParam = cmd.CreateParameter();
idParam.ParameterName = "ID";
idParam.Value = this.Id;
cmd.Parameters.Add(idParam);
}
#endregion
}
}

View File

@ -0,0 +1,109 @@
using System.Data;
namespace brecal.model
{
public class SecurableAssignment : DbEntity
{
#region Properties
public Role? AssignedRole { get; set; }
public Securable? AssignedSecurable { get; set; }
public int? RoleId { get; set; }
public int? SecurableId { get; set; }
#endregion
#region public static methods
public static async Task<List<SecurableAssignment>> LoadForRole(Role? r, IDBManager manager)
{
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems, args: r);
List<SecurableAssignment> result = new();
foreach (SecurableAssignment sa in loadResultList.Cast<SecurableAssignment>())
{
sa.AssignedRole = r;
result.Add(sa);
}
return result;
}
public static void SetLoadQuery(IDbCommand cmd, params object?[] args)
{
cmd.CommandText = "SELECT id, role_id, securable_id FROM role_securable_map WHERE role_id = @RID";
if (args.Length != 1 || !(args[0] is Role))
throw new ArgumentException("loader needs single role as argument");
IDataParameter rid = cmd.CreateParameter();
rid.ParameterName = "RID";
if (args[0] is Role r)
rid.Value = r.Id;
cmd.Parameters.Add(rid);
}
public static List<DbEntity> LoadElems(IDataReader reader)
{
List<DbEntity> result = new List<DbEntity>();
while (reader.Read())
{
SecurableAssignment sa = new();
sa.Id = (uint)reader.GetInt32(0);
if (!reader.IsDBNull(1)) sa.RoleId = reader.GetInt32(1);
if (!reader.IsDBNull(2)) sa.SecurableId = reader.GetInt32(2);
result.Add(sa);
}
return result;
}
#endregion
#region public overrides
public override void SetUpdate(IDbCommand cmd)
{
throw new NotImplementedException();
}
public override void SetCreate(IDbCommand cmd)
{
cmd.CommandText = "INSERT INTO role_securable_map (securable_id, role_id) VALUES (@SECURABLEID, @ROLEID)";
IDbDataParameter userid = cmd.CreateParameter();
userid.ParameterName = "SECURABLEID";
userid.Value = this.SecurableId;
cmd.Parameters.Add(userid);
IDbDataParameter roleid = cmd.CreateParameter();
roleid.ParameterName = "ROLEID";
roleid.Value = this.RoleId;
cmd.Parameters.Add(roleid);
}
public override void SetDelete(IDbCommand cmd)
{
cmd.CommandText = "DELETE FROM role_securable_map WHERE id = @ID";
IDataParameter idParam = cmd.CreateParameter();
idParam.ParameterName = "ID";
idParam.Value = this.Id;
cmd.Parameters.Add(idParam);
}
public override string ToString()
{
if (this.AssignedSecurable == null)
{
return $"{Id}: <defunct securable>";
}
else
{
return AssignedSecurable.Name ?? AssignedSecurable.Id.ToString();
}
}
#endregion
}
}

143
src/brecal.model/User.cs Normal file
View File

@ -0,0 +1,143 @@
using System.Data;
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; }
public uint? Participant_Id { get; set; }
#endregion
#region public static methods
public static async Task<List<User>> LoadForParticipant(Participant? p, IDBManager manager)
{
List<DbEntity> loadResultList = await manager.Load(SetLoadQuery, LoadElems, args: p);
List<User> result = new();
foreach (User u in loadResultList.Cast<User>())
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";
if (args[0] is Participant p)
pid.Value = p.Id;
cmd.Parameters.Add(pid);
}
public static List<DbEntity> LoadElems(IDataReader reader)
{
List<DbEntity> result = new List<DbEntity>();
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 override void SetUpdate(IDbCommand cmd)
{
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)
{
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)
{
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()
{
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
}
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,54 @@
using brecal.model;
using MySqlConnector;
using System.Data;
using System.Runtime.CompilerServices;
using static brecal.model.IDBManager;
namespace brecal.mysql
{
public class DBManager : IDBManager
{
// TODO: remove this and use external configuration
private static readonly string _connectionString = "Server=localhost;User ID=ds;Password=HalloWach23;Database=bremen_calling";
public async Task<List<DbEntity>> Load(QueryFunc prepareAction, LoadFunc<IDataReader> loadAction, params object?[] args)
{
await using MySqlConnection connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
using MySqlCommand cmd = new();
cmd.Connection = connection;
prepareAction(cmd, args);
MySqlDataReader reader = await cmd.ExecuteReaderAsync();
List<DbEntity> result = loadAction(reader);
reader.Close();
return result;
}
public async Task<object?> ExecuteScalar(Action<IDbCommand> prepareAction)
{
await using MySqlConnection connection = new MySqlConnection(_connectionString);
await connection.OpenAsync();
using MySqlCommand cmd = new();
cmd.Connection = connection;
prepareAction(cmd);
object? result = await cmd.ExecuteScalarAsync();
return result;
}
public async Task<int> ExecuteNonQuery(Action<IDbCommand> prepareAction)
{
await using MySqlConnection connection = new(_connectionString);
await connection.OpenAsync();
using MySqlCommand cmd = new();
cmd.Connection = connection;
prepareAction(cmd);
await cmd.ExecuteNonQueryAsync();
int result = (int)cmd.LastInsertedId;
return result;
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySqlConnector" Version="2.3.0-beta.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\brecal.model\brecal.model.csproj" />
</ItemGroup>
</Project>

View File

@ -8,7 +8,7 @@ def initPool():
try:
global connection_pool
connection_pool = mysql.connector.connect(
host="lager",
host="lager", # TODO: move these settings outside the code!
port=3306,
user="ds",
password="HalloWach23",