Compare commits

...

4 Commits
main ... Lab4

154 changed files with 5408 additions and 55 deletions

View File

@ -3,9 +3,23 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35004.147
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PutincevLibrary", "PutincevLibrary\PutincevLibrary.csproj", "{BF0238D4-F38A-4670-8479-E8F6FE980F15}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PutincevLibrary", "PutincevLibrary\PutincevLibrary.csproj", "{BF0238D4-F38A-4670-8479-E8F6FE980F15}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinForms", "WinForms\WinForms.csproj", "{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinForms", "WinForms\WinForms.csproj", "{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsBusinessLogic", "PortalAccountsBusinessLogic\PortalAccountsBusinessLogic.csproj", "{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsContracts", "PortalAccountsContracts\PortalAccountsContracts.csproj", "{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsDatabaseImplement", "PortalAccountsDatabaseImplement\PortalAccountsDatabaseImplement.csproj", "{F39F4D94-6F88-472C-958A-41F523E5C458}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsDataModels", "PortalAccountsDataModels\PortalAccountsDataModels.csproj", "{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortalAccountsView", "PortalAccountsView\PortalAccountsView.csproj", "{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginsApp", "PluginsApp\PluginsApp.csproj", "{9A329DF5-120D-4695-9E0D-F0727649C16D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginsConventionLibrary", "PluginsConventionLibrary\PluginsConventionLibrary.csproj", "{93871BA7-1708-4403-B01B-8D16B0D140C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -21,6 +35,34 @@ Global
{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DC08E58-4198-4F93-8CF2-ECE1A757AF61}.Release|Any CPU.Build.0 = Release|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F05412C2-09F2-40F7-9E20-1E97E1E61DD6}.Release|Any CPU.Build.0 = Release|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E3D8AF4-E505-45AE-815A-9E24F90A5E0A}.Release|Any CPU.Build.0 = Release|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F39F4D94-6F88-472C-958A-41F523E5C458}.Release|Any CPU.Build.0 = Release|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA4B05BE-8AEB-4D83-9381-53493BFFBCA1}.Release|Any CPU.Build.0 = Release|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36667C40-A6AE-422B-BFD2-BCEEC0A54EA2}.Release|Any CPU.Build.0 = Release|Any CPU
{9A329DF5-120D-4695-9E0D-F0727649C16D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A329DF5-120D-4695-9E0D-F0727649C16D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A329DF5-120D-4695-9E0D-F0727649C16D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A329DF5-120D-4695-9E0D-F0727649C16D}.Release|Any CPU.Build.0 = Release|Any CPU
{93871BA7-1708-4403-B01B-8D16B0D140C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{93871BA7-1708-4403-B01B-8D16B0D140C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{93871BA7-1708-4403-B01B-8D16B0D140C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{93871BA7-1708-4403-B01B-8D16B0D140C4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

173
COP/PluginsApp/FormMain.Designer.cs generated Normal file
View File

@ -0,0 +1,173 @@
namespace PluginsApp
{
partial class FormMain
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
menuStrip = new MenuStrip();
ControlsStripMenuItem = new ToolStripMenuItem();
ActionsToolStripMenuItem = new ToolStripMenuItem();
ThesaurusToolStripMenuItem = new ToolStripMenuItem();
AddElementToolStripMenuItem = new ToolStripMenuItem();
UpdElementToolStripMenuItem = new ToolStripMenuItem();
DelElementToolStripMenuItem = new ToolStripMenuItem();
DocsToolStripMenuItem = new ToolStripMenuItem();
SimpleDocToolStripMenuItem = new ToolStripMenuItem();
TableDocToolStripMenuItem = new ToolStripMenuItem();
ChartDocToolStripMenuItem = new ToolStripMenuItem();
panelControl = new Panel();
menuStrip.SuspendLayout();
SuspendLayout();
//
// menuStrip
//
menuStrip.Items.AddRange(new ToolStripItem[] { ControlsStripMenuItem, ActionsToolStripMenuItem, DocsToolStripMenuItem });
menuStrip.Location = new Point(0, 0);
menuStrip.Name = "menuStrip";
menuStrip.Size = new Size(800, 24);
menuStrip.TabIndex = 0;
menuStrip.Text = "Меню";
//
// ControlsStripMenuItem
//
ControlsStripMenuItem.Name = "ControlsStripMenuItem";
ControlsStripMenuItem.Size = new Size(90, 20);
ControlsStripMenuItem.Text = "Компоненты";
//
// ActionsToolStripMenuItem
//
ActionsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { ThesaurusToolStripMenuItem, AddElementToolStripMenuItem, UpdElementToolStripMenuItem, DelElementToolStripMenuItem });
ActionsToolStripMenuItem.Name = "ActionsToolStripMenuItem";
ActionsToolStripMenuItem.Size = new Size(70, 20);
ActionsToolStripMenuItem.Text = "Действия";
//
// ThesaurusToolStripMenuItem
//
ThesaurusToolStripMenuItem.Name = "ThesaurusToolStripMenuItem";
ThesaurusToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.I;
ThesaurusToolStripMenuItem.Size = new Size(180, 22);
ThesaurusToolStripMenuItem.Text = "Справочник";
ThesaurusToolStripMenuItem.Click += ThesaurusToolStripMenuItem_Click;
//
// AddElementToolStripMenuItem
//
AddElementToolStripMenuItem.Name = "AddElementToolStripMenuItem";
AddElementToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.A;
AddElementToolStripMenuItem.Size = new Size(180, 22);
AddElementToolStripMenuItem.Text = "Добавить";
AddElementToolStripMenuItem.Click += AddElementToolStripMenuItem_Click;
//
// UpdElementToolStripMenuItem
//
UpdElementToolStripMenuItem.Name = "UpdElementToolStripMenuItem";
UpdElementToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.U;
UpdElementToolStripMenuItem.Size = new Size(180, 22);
UpdElementToolStripMenuItem.Text = "Изменить";
UpdElementToolStripMenuItem.Click += UpdElementToolStripMenuItem_Click;
//
// DelElementToolStripMenuItem
//
DelElementToolStripMenuItem.Name = "DelElementToolStripMenuItem";
DelElementToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.D;
DelElementToolStripMenuItem.Size = new Size(180, 22);
DelElementToolStripMenuItem.Text = "Удалить";
DelElementToolStripMenuItem.Click += DelElementToolStripMenuItem_Click;
//
// DocsToolStripMenuItem
//
DocsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { SimpleDocToolStripMenuItem, TableDocToolStripMenuItem, ChartDocToolStripMenuItem });
DocsToolStripMenuItem.Name = "DocsToolStripMenuItem";
DocsToolStripMenuItem.Size = new Size(82, 20);
DocsToolStripMenuItem.Text = "Документы";
//
// SimpleDocToolStripMenuItem
//
SimpleDocToolStripMenuItem.Name = "SimpleDocToolStripMenuItem";
SimpleDocToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.S;
SimpleDocToolStripMenuItem.Size = new Size(232, 22);
SimpleDocToolStripMenuItem.Text = "Простой документ";
SimpleDocToolStripMenuItem.Click += SimpleDocToolStripMenuItem_Click;
//
// TableDocToolStripMenuItem
//
TableDocToolStripMenuItem.Name = "TableDocToolStripMenuItem";
TableDocToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.T;
TableDocToolStripMenuItem.Size = new Size(232, 22);
TableDocToolStripMenuItem.Text = "Документ с таблицей";
TableDocToolStripMenuItem.Click += TableDocToolStripMenuItem_Click;
//
// ChartDocToolStripMenuItem
//
ChartDocToolStripMenuItem.Name = "ChartDocToolStripMenuItem";
ChartDocToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.C;
ChartDocToolStripMenuItem.Size = new Size(232, 22);
ChartDocToolStripMenuItem.Text = "Диаграмма";
ChartDocToolStripMenuItem.Click += ChartDocToolStripMenuItem_Click;
//
// panelControl
//
panelControl.Dock = DockStyle.Fill;
panelControl.Location = new Point(0, 24);
panelControl.Name = "panelControl";
panelControl.Size = new Size(800, 426);
panelControl.TabIndex = 1;
//
// FormMain
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(panelControl);
Controls.Add(menuStrip);
MainMenuStrip = menuStrip;
Name = "FormMain";
StartPosition = FormStartPosition.CenterScreen;
Text = "Главная форма";
WindowState = FormWindowState.Maximized;
KeyDown += FormMain_KeyDown;
menuStrip.ResumeLayout(false);
menuStrip.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.MenuStrip menuStrip;
private System.Windows.Forms.ToolStripMenuItem ControlsStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem DocsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem SimpleDocToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem TableDocToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem ChartDocToolStripMenuItem;
private System.Windows.Forms.Panel panelControl;
private System.Windows.Forms.ToolStripMenuItem ActionsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem ThesaurusToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem AddElementToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem UpdElementToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem DelElementToolStripMenuItem;
}
}

243
COP/PluginsApp/FormMain.cs Normal file
View File

@ -0,0 +1,243 @@
using PluginsConventionLibrary;
using System.Reflection;
namespace PluginsApp
{
public partial class FormMain : Form
{
private readonly Dictionary<string, IPluginsConvention> _plugins;
private string _selectedPlugin;
public FormMain()
{
InitializeComponent();
_plugins = LoadPlugins();
_selectedPlugin = string.Empty;
}
private Dictionary<string, IPluginsConvention> LoadPlugins()
{
var plugins = new Dictionary<string, IPluginsConvention>();
string pluginsDir = Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory())!.Parent!.Parent!.FullName, "Plugins");
if (!Directory.Exists(pluginsDir))
{
MessageBox.Show($"Êàòàëîã {pluginsDir} íå íàéäåí.", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
return plugins;
}
foreach (string dllFile in Directory.EnumerateFiles(pluginsDir, "*.dll", SearchOption.AllDirectories))
{
try
{
Assembly assembly = Assembly.LoadFrom(dllFile);
Type[] types = assembly.GetTypes();
foreach (var type in types)
{
if (typeof(IPluginsConvention).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
{
var plugin = (IPluginsConvention)Activator.CreateInstance(type)!;
plugins.Add(plugin.PluginName, plugin);
CreateToolStripMenuItem(plugin.PluginName);
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Îøèáêà ïðè çàãðóçêå ñáîðêè {dllFile}: {ex.Message}", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
return plugins;
}
private void CreateToolStripMenuItem(string pluginName)
{
var menuItem = new ToolStripMenuItem(pluginName);
menuItem.Click += (object? sender, EventArgs e) =>
{
_selectedPlugin = pluginName;
IPluginsConvention plugin = _plugins![pluginName];
UserControl userControl = plugin?.GetControl ?? throw new Exception("Ïðîáëåìà ñ çàãðóçêîé ýëåìåíòà äëÿ âûâîäà äàííûõ");
panelControl.Controls.Clear();
plugin.ReloadData();
userControl.Dock = DockStyle.Fill;
panelControl.Controls.Add(userControl);
};
ControlsStripMenuItem.DropDownItems.Add(menuItem);
}
private void FormMain_KeyDown(object sender, KeyEventArgs e)
{
if (string.IsNullOrEmpty(_selectedPlugin) || !_plugins.ContainsKey(_selectedPlugin))
{
return;
}
if (!e.Control)
{
return;
}
switch (e.KeyCode)
{
case Keys.I:
ShowThesaurus();
break;
case Keys.A:
AddNewElement();
break;
case Keys.U:
UpdateElement();
break;
case Keys.D:
DeleteElement();
break;
case Keys.S:
CreateSimpleDoc();
break;
case Keys.T:
CreateTableDoc();
break;
case Keys.C:
CreateChartDoc();
break;
}
}
private void ShowThesaurus()
{
_plugins[_selectedPlugin].GetThesaurus()?.Show();
}
private void AddNewElement()
{
var form = _plugins[_selectedPlugin].GetForm(null);
if (form != null && form.ShowDialog() == DialogResult.OK)
{
_plugins[_selectedPlugin].ReloadData();
}
}
private void UpdateElement()
{
var element = _plugins[_selectedPlugin].GetElement;
if (element == null)
{
MessageBox.Show("Íåò âûáðàííîãî ýëåìåíòà", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var form = _plugins[_selectedPlugin].GetForm(element);
if (form != null && form.ShowDialog() == DialogResult.OK)
{
_plugins[_selectedPlugin].ReloadData();
}
}
private void DeleteElement()
{
if (MessageBox.Show("Óäàëèòü âûáðàííûé ýëåìåíò", "Óäàëåíèå", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
{
return;
}
var element = _plugins[_selectedPlugin].GetElement;
if (element == null)
{
MessageBox.Show("Íåò âûáðàííîãî ýëåìåíòà", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (_plugins[_selectedPlugin].DeleteElement(element))
{
_plugins[_selectedPlugin].ReloadData();
}
}
private void CreateSimpleDoc()
{
using var dialog = new SaveFileDialog
{
Filter = "docx|*.docx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
if (_plugins[_selectedPlugin].CreateSimpleDocument(new PluginsConventionSaveDocument() { FileName = dialog.FileName } ))
{
MessageBox.Show("Äîêóìåíò ñîõðàíåí", "Ñîçäàíèå äîêóìåíòà", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Îøèáêà ïðè ñîçäàíèè äîêóìåíòà", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show("Ïðîèçîøëà îøèáêà: " + ex.Message, "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void CreateTableDoc()
{
using var dialog = new SaveFileDialog
{
Filter = "PDF Files|*.pdf"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
if (_plugins[_selectedPlugin].CreateTableDocument(new PluginsConventionSaveDocument() { FileName = dialog.FileName }))
{
MessageBox.Show("Äîêóìåíò ñîõðàíåí", "Ñîçäàíèå äîêóìåíòà", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Îøèáêà ïðè ñîçäàíèè äîêóìåíòà", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show("Ïðîèçîøëà îøèáêà: " + ex.Message, "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void CreateChartDoc()
{
using var dialog = new SaveFileDialog
{
Filter = "Excel Files|*.xlsx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
if (_plugins[_selectedPlugin].CreateChartDocument(new PluginsConventionSaveDocument() { FileName = dialog.FileName }))
{
MessageBox.Show("Äîêóìåíò ñîõðàíåí", "Ñîçäàíèå äîêóìåíòà", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Îøèáêà ïðè ñîçäàíèè äîêóìåíòà", "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show("Ïðîèçîøëà îøèáêà: " + ex.Message, "Îøèáêà", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ThesaurusToolStripMenuItem_Click(object sender, EventArgs e) => ShowThesaurus();
private void AddElementToolStripMenuItem_Click(object sender, EventArgs e) => AddNewElement();
private void UpdElementToolStripMenuItem_Click(object sender, EventArgs e) => UpdateElement();
private void DelElementToolStripMenuItem_Click(object sender, EventArgs e) => DeleteElement();
private void SimpleDocToolStripMenuItem_Click(object sender, EventArgs e) => CreateSimpleDoc();
private void TableDocToolStripMenuItem_Click(object sender, EventArgs e) => CreateTableDoc();
private void ChartDocToolStripMenuItem_Click(object sender, EventArgs e) => CreateChartDoc();
}
}

View File

@ -0,0 +1,123 @@
<?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>
<metadata name="menuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PluginsConventionLibrary\PluginsConventionLibrary.csproj" />
</ItemGroup>
</Project>

17
COP/PluginsApp/Program.cs Normal file
View File

@ -0,0 +1,17 @@
namespace PluginsApp
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new FormMain());
}
}
}

View File

@ -0,0 +1,66 @@
namespace PluginsConventionLibrary
{
public interface IPluginsConvention
{
/// <summary>
/// Название плагина
/// </summary>
string PluginName { get; }
/// <summary>
/// Получение контрола для вывода набора данных
/// </summary>
UserControl GetControl { get; }
/// <summary>
/// Получение элемента, выбранного в контроле
/// </summary>
PluginsConventionElement GetElement { get; }
/// <summary>
/// Получение формы для создания/редактирования объекта
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
Form GetForm(PluginsConventionElement element);
/// <summary>
/// Получение формы для работы со справочником
/// </summary>
/// <returns></returns>
Form GetThesaurus();
/// <summary>
/// Удаление элемента
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
bool DeleteElement(PluginsConventionElement element);
/// <summary>
/// Обновление набора данных в контроле
/// </summary>
void ReloadData();
/// <summary>
/// Создание простого документа
/// </summary>
/// <param name="saveDocument"></param>
/// <returns></returns>
bool CreateSimpleDocument(PluginsConventionSaveDocument saveDocument);
/// <summary>
/// Создание документа с таблицей
/// </summary>
/// <param name="saveDocument"></param>
/// <returns></returns>
bool CreateTableDocument(PluginsConventionSaveDocument saveDocument);
/// <summary>
/// Создание документа с диаграммой
/// </summary>
/// <param name="saveDocument"></param>
/// <returns></returns>
bool CreateChartDocument(PluginsConventionSaveDocument saveDocument);
}
}

View File

@ -0,0 +1,7 @@
namespace PluginsConventionLibrary
{
public class PluginsConventionElement
{
public Guid Id { get; set; }
}
}

View File

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

View File

@ -0,0 +1,7 @@
namespace PluginsConventionLibrary
{
public class PluginsConventionSaveDocument
{
public string FileName { get; set; }
}
}

View File

@ -0,0 +1,78 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsBusinessLogic.BusinessLogics
{
public class AccountLogic : IAccountLogic
{
private readonly IAccountStorage _accountStorage;
public AccountLogic(IAccountStorage AccountStorage)
{
_accountStorage = AccountStorage;
}
public List<AccountViewModel>? ReadList(AccountSearchModel? model)
{
return model == null ? _accountStorage.GetFullList() : _accountStorage.GetFilteredList(model);
}
public AccountViewModel? ReadElement(AccountSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
return _accountStorage.GetElement(model);
}
public bool Create(AccountBindingModel model)
{
CheckModel(model);
return _accountStorage.Insert(model) != null;
}
public bool Update(AccountBindingModel model)
{
CheckModel(model);
return _accountStorage.Update(model) != null;
}
public bool Delete(AccountBindingModel model)
{
CheckModel(model, false);
return _accountStorage.Delete(model) != null;
}
private void CheckModel(AccountBindingModel model, bool withParams = true)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
if (!withParams)
{
return;
}
if (string.IsNullOrEmpty(model.Login))
{
throw new ArgumentNullException("Нет логина у аккаунта", nameof(model.Login));
}
if (model.InterestId <= 0)
{
throw new ArgumentNullException("Некорректный идентификатор интерес", nameof(model.InterestId));
}
var element = _accountStorage.GetElement(new AccountSearchModel
{
Login = model.Login
});
if (element != null && element.Id != model.Id)
{
throw new InvalidOperationException("Аккаунт с таким логином уже есть");
}
}
}
}

View File

@ -0,0 +1,74 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsBusinessLogic.BusinessLogics
{
public class InterestLogic : IInterestLogic
{
private readonly IInterestStorage _interestStorage;
public InterestLogic(IInterestStorage InterestStorage)
{
_interestStorage = InterestStorage;
}
public List<InterestViewModel>? ReadList(InterestSearchModel? model)
{
return model == null ? _interestStorage.GetFullList() : _interestStorage.GetFilteredList(model);
}
public InterestViewModel? ReadElement(InterestSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
return _interestStorage.GetElement(model);
}
public bool Create(InterestBindingModel model)
{
CheckModel(model);
return _interestStorage.Insert(model) != null;
}
public bool Update(InterestBindingModel model)
{
CheckModel(model);
return _interestStorage.Update(model) != null;
}
public bool Delete(InterestBindingModel model)
{
CheckModel(model, false);
return _interestStorage.Delete(model) != null;
}
private void CheckModel(InterestBindingModel model, bool withParams = true)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
if (!withParams)
{
return;
}
if (string.IsNullOrEmpty(model.Name))
{
throw new ArgumentNullException("Нет названия интерес", nameof(model.Name));
}
var element = _interestStorage.GetElement(new InterestSearchModel
{
Name = model.Name
});
if (element != null && element.Id != model.Id)
{
throw new InvalidOperationException("Интерес с таким названием уже есть");
}
}
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsContracts\PortalAccountsContracts.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,17 @@
using PortalAccountsDataModels.Models;
namespace PortalAccountsContracts.BindingModels
{
public class AccountBindingModel : IAccountModel
{
public int Id { get; set; }
public string Login { get; set; } = string.Empty;
public string? AvatarPath { get; set; }
public int InterestId { get; set; }
public string? Email { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using PortalAccountsDataModels.Models;
namespace PortalAccountsContracts.BindingModels
{
public class InterestBindingModel : IInterestModel
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,19 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.BusinessLogicsContracts
{
public interface IAccountLogic
{
List<AccountViewModel>? ReadList(AccountSearchModel? model);
AccountViewModel? ReadElement(AccountSearchModel model);
bool Create(AccountBindingModel model);
bool Update(AccountBindingModel model);
bool Delete(AccountBindingModel model);
}
}

View File

@ -0,0 +1,19 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.BusinessLogicsContracts
{
public interface IInterestLogic
{
List<InterestViewModel>? ReadList(InterestSearchModel? model);
InterestViewModel? ReadElement(InterestSearchModel model);
bool Create(InterestBindingModel model);
bool Update(InterestBindingModel model);
bool Delete(InterestBindingModel model);
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsDataModels\PortalAccountsDataModels.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,11 @@
namespace PortalAccountsContracts.SearchModels
{
public class AccountSearchModel
{
public int? Id { get; set; }
public string? Login { get; set; }
public int? InterestId { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace PortalAccountsContracts.SearchModels
{
public class InterestSearchModel
{
public int? Id { get; set; }
public string? Name { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.StoragesContracts
{
public interface IAccountStorage
{
List<AccountViewModel> GetFullList();
List<AccountViewModel> GetFilteredList(AccountSearchModel model);
AccountViewModel? GetElement(AccountSearchModel model);
AccountViewModel? Insert(AccountBindingModel model);
AccountViewModel? Update(AccountBindingModel model);
AccountViewModel? Delete(AccountBindingModel model);
}
}

View File

@ -0,0 +1,21 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
namespace PortalAccountsContracts.StoragesContracts
{
public interface IInterestStorage
{
List<InterestViewModel> GetFullList();
List<InterestViewModel> GetFilteredList(InterestSearchModel model);
InterestViewModel? GetElement(InterestSearchModel model);
InterestViewModel? Insert(InterestBindingModel model);
InterestViewModel? Update(InterestBindingModel model);
InterestViewModel? Delete(InterestBindingModel model);
}
}

View File

@ -0,0 +1,24 @@
using PortalAccountsDataModels.Models;
using System.ComponentModel;
namespace PortalAccountsContracts.ViewModels
{
public class AccountViewModel : IAccountModel
{
public int Id { get; set; }
[DisplayName("Логин")]
public string Login { get; set; } = string.Empty;
public string? AvatarPath { get; set; }
public int InterestId { get; set; }
[DisplayName("Интерес")]
public string InterestName { get; set; } = string.Empty;
[DisplayName("Почта")]
public string? Email { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using PortalAccountsDataModels.Models;
using System.ComponentModel;
namespace PortalAccountsContracts.ViewModels
{
public class InterestViewModel : IInterestModel
{
public int Id { get; set; }
[DisplayName("Название интереса")]
public string Name { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,7 @@
namespace PortalAccountsDataModels
{
public interface IId
{
int Id { get; }
}
}

View File

@ -0,0 +1,13 @@
namespace PortalAccountsDataModels.Models
{
public interface IAccountModel : IId
{
string Login { get; }
string? AvatarPath { get; }
int InterestId { get; }
string? Email { get; }
}
}

View File

@ -0,0 +1,7 @@
namespace PortalAccountsDataModels.Models
{
public interface IInterestModel : IId
{
string Name { get; }
}
}

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,98 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
namespace PortalAccountsDatabaseImplement.Implements
{
public class AccountStorage : IAccountStorage
{
public List<AccountViewModel> GetFullList()
{
using var context = new PortalAccountsDatabase();
return context.Accounts
.Include(x => x.Interest)
.Select(x => x.GetViewModel)
.ToList();
}
public List<AccountViewModel> GetFilteredList(AccountSearchModel model)
{
using var context = new PortalAccountsDatabase();
if (model.InterestId.HasValue)
{
return context.Accounts
.Include(x => x.Interest)
.Where(x => x.InterestId == model.InterestId)
.Select(x => x.GetViewModel)
.ToList();
}
return new();
}
public AccountViewModel? GetElement(AccountSearchModel model)
{
if (string.IsNullOrEmpty(model.Login) && !model.Id.HasValue)
{
return null;
}
using var context = new PortalAccountsDatabase();
return context.Accounts
.Include(x => x.Interest)
.FirstOrDefault(x => !string.IsNullOrEmpty(model.Login) && x.Login == model.Login ||
model.Id.HasValue && x.Id == model.Id)
?.GetViewModel;
}
public AccountViewModel? Insert(AccountBindingModel model)
{
var newAccount = Account.Create(model);
if (newAccount == null)
{
return null;
}
using var context = new PortalAccountsDatabase();
context.Accounts.Add(newAccount);
context.SaveChanges();
return context.Accounts
.Include(x => x.Interest)
.FirstOrDefault(x => x.Id == newAccount.Id)
?.GetViewModel;
}
public AccountViewModel? Update(AccountBindingModel model)
{
using var context = new PortalAccountsDatabase();
var account = context.Accounts.FirstOrDefault(x => x.Id == model.Id);
if (account == null)
{
return null;
}
account.Update(model);
context.SaveChanges();
return context.Accounts
.Include(x => x.Interest)
.FirstOrDefault(x => x.Id == model.Id)
?.GetViewModel;
}
public AccountViewModel? Delete(AccountBindingModel model)
{
using var context = new PortalAccountsDatabase();
var element = context.Accounts.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
{
var deletedElement = context.Accounts
.Include(x => x.Interest)
.FirstOrDefault(x => x.Id == model.Id)
?.GetViewModel;
context.Accounts.Remove(element);
context.SaveChanges();
return deletedElement;
}
return null;
}
}
}

View File

@ -0,0 +1,84 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.StoragesContracts;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDatabaseImplement.Models;
namespace PortalAccountsDatabaseImplement.Implements
{
public class InterestStorage : IInterestStorage
{
public List<InterestViewModel> GetFullList()
{
using var context = new PortalAccountsDatabase();
return context.Interests
.Select(x => x.GetViewModel)
.ToList();
}
public List<InterestViewModel> GetFilteredList(InterestSearchModel model)
{
if (string.IsNullOrEmpty(model.Name))
{
return new();
}
using var context = new PortalAccountsDatabase();
return context.Interests
.Where(x => x.Name.Contains(model.Name))
.Select(x => x.GetViewModel)
.ToList();
}
public InterestViewModel? GetElement(InterestSearchModel model)
{
if (string.IsNullOrEmpty(model.Name) && !model.Id.HasValue)
{
return null;
}
using var context = new PortalAccountsDatabase();
return context.Interests
.FirstOrDefault(x => !string.IsNullOrEmpty(model.Name) && x.Name == model.Name ||
model.Id.HasValue && x.Id == model.Id)
?.GetViewModel;
}
public InterestViewModel? Insert(InterestBindingModel model)
{
var newInterest = Interest.Create(model);
if (newInterest == null)
{
return null;
}
using var context = new PortalAccountsDatabase();
context.Interests.Add(newInterest);
context.SaveChanges();
return newInterest.GetViewModel;
}
public InterestViewModel? Update(InterestBindingModel model)
{
using var context = new PortalAccountsDatabase();
var interest = context.Interests.FirstOrDefault(x => x.Id == model.Id);
if (interest == null)
{
return null;
}
interest.Update(model);
context.SaveChanges();
return interest.GetViewModel;
}
public InterestViewModel? Delete(InterestBindingModel model)
{
using var context = new PortalAccountsDatabase();
var element = context.Interests.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
{
context.Interests.Remove(element);
context.SaveChanges();
return element.GetViewModel;
}
return null;
}
}
}

View File

@ -0,0 +1,90 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using PortalAccountsDatabaseImplement;
#nullable disable
namespace PortalAccountsDatabaseImplement.Migrations
{
[DbContext(typeof(PortalAccountsDatabase))]
[Migration("20241106113420_migr")]
partial class migr
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("AvatarPath")
.HasColumnType("text");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("InterestId")
.HasColumnType("integer");
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("InterestId");
b.ToTable("Accounts");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Interests");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.HasOne("PortalAccountsDatabaseImplement.Models.Interest", "Interest")
.WithMany("Accounts")
.HasForeignKey("InterestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Interest");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,65 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace PortalAccountsDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class migr : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Interests",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Interests", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Accounts",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Login = table.Column<string>(type: "text", nullable: false),
AvatarPath = table.Column<string>(type: "text", nullable: true),
InterestId = table.Column<int>(type: "integer", nullable: false),
Email = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Accounts", x => x.Id);
table.ForeignKey(
name: "FK_Accounts_Interests_InterestId",
column: x => x.InterestId,
principalTable: "Interests",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Accounts_InterestId",
table: "Accounts",
column: "InterestId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Accounts");
migrationBuilder.DropTable(
name: "Interests");
}
}
}

View File

@ -0,0 +1,87 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using PortalAccountsDatabaseImplement;
#nullable disable
namespace PortalAccountsDatabaseImplement.Migrations
{
[DbContext(typeof(PortalAccountsDatabase))]
partial class PortalAccountsDatabaseModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("AvatarPath")
.HasColumnType("text");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("InterestId")
.HasColumnType("integer");
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("InterestId");
b.ToTable("Accounts");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Interests");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Account", b =>
{
b.HasOne("PortalAccountsDatabaseImplement.Models.Interest", "Interest")
.WithMany("Accounts")
.HasForeignKey("InterestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Interest");
});
modelBuilder.Entity("PortalAccountsDatabaseImplement.Models.Interest", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,62 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDataModels.Models;
using System.ComponentModel.DataAnnotations;
namespace PortalAccountsDatabaseImplement.Models
{
public class Account : IAccountModel
{
public int Id { get; private set; }
[Required]
public string Login { get; set; } = string.Empty;
public string? AvatarPath { get; set; }
[Required]
public int InterestId { get; set; }
public string? Email { get; set; }
public virtual Interest Interest { get; set; }
public static Account? Create(AccountBindingModel? model)
{
if (model == null)
{
return null;
}
return new Account()
{
Id = model.Id,
Login = model.Login,
AvatarPath = model.AvatarPath,
InterestId = model.InterestId,
Email = model.Email
};
}
public void Update(AccountBindingModel? model)
{
if (model == null)
{
return;
}
Login = model.Login;
AvatarPath = model.AvatarPath;
InterestId = model.InterestId;
Email = model.Email;
}
public AccountViewModel GetViewModel => new()
{
Id = Id,
Login = Login,
AvatarPath = AvatarPath,
InterestId = InterestId,
InterestName = Interest.Name ?? string.Empty,
Email = Email
};
}
}

View File

@ -0,0 +1,48 @@
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.ViewModels;
using PortalAccountsDataModels.Models;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PortalAccountsDatabaseImplement.Models
{
public class Interest : IInterestModel
{
public int Id { get; private set; }
[Required]
public string Name { get; private set; } = string.Empty;
[ForeignKey("InterestId")]
public virtual List<Account> Accounts { get; set; } = new();
public static Interest? Create(InterestBindingModel model)
{
if (model == null)
{
return null;
}
return new Interest()
{
Id = model.Id,
Name = model.Name
};
}
public void Update(InterestBindingModel model)
{
if (model == null)
{
return;
}
Name = model.Name;
}
public InterestViewModel GetViewModel => new()
{
Id = Id,
Name = Name
};
}
}

View File

@ -0,0 +1,23 @@
using PortalAccountsDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
namespace PortalAccountsDatabaseImplement
{
public class PortalAccountsDatabase : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured == false)
{
optionsBuilder.UseNpgsql(@"Host=localhost;Port=6456;Database=put_portal_accounts_database;Username=postgres;Password=dan");
}
base.OnConfiguring(optionsBuilder);
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
public virtual DbSet<Account> Accounts { set; get; }
public virtual DbSet<Interest> Interests { set; get; }
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PortalAccountsContracts\PortalAccountsContracts.csproj" />
<ProjectReference Include="..\PortalAccountsDataModels\PortalAccountsDataModels.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,169 @@
namespace PortalAccountsView
{
partial class FormAccount
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
labelLogin = new Label();
labelInterest = new Label();
labelAvatar = new Label();
labelEmail = new Label();
buttonSave = new Button();
buttonCancel = new Button();
textBoxLogin = new TextBox();
customListBoxInterest = new Components.CustomListBox();
textBoxControlEmail = new RodionovLibrary.VisualComponents.TextBoxControl();
textBoxAvatar = new TextBox();
SuspendLayout();
//
// labelLogin
//
labelLogin.AutoSize = true;
labelLogin.Location = new Point(39, 17);
labelLogin.Name = "labelLogin";
labelLogin.Size = new Size(52, 20);
labelLogin.TabIndex = 0;
labelLogin.Text = "Логин";
//
// labelInterest
//
labelInterest.AutoSize = true;
labelInterest.Location = new Point(39, 99);
labelInterest.Name = "labelInterest";
labelInterest.Size = new Size(67, 20);
labelInterest.TabIndex = 1;
labelInterest.Text = "Интерес";
//
// labelAvatar
//
labelAvatar.AutoSize = true;
labelAvatar.Location = new Point(570, 17);
labelAvatar.Name = "labelAvatar";
labelAvatar.Size = new Size(58, 20);
labelAvatar.TabIndex = 2;
labelAvatar.Text = "Аватар";
//
// labelEmail
//
labelEmail.AutoSize = true;
labelEmail.Location = new Point(570, 138);
labelEmail.Name = "labelEmail";
labelEmail.Size = new Size(51, 20);
labelEmail.TabIndex = 3;
labelEmail.Text = "Почта";
//
// buttonSave
//
buttonSave.Location = new Point(277, 352);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(105, 36);
buttonSave.TabIndex = 9;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// buttonCancel
//
buttonCancel.Location = new Point(470, 352);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(105, 36);
buttonCancel.TabIndex = 10;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// textBoxLogin
//
textBoxLogin.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
textBoxLogin.Location = new Point(39, 56);
textBoxLogin.Name = "textBoxLogin";
textBoxLogin.Size = new Size(226, 27);
textBoxLogin.TabIndex = 11;
textBoxLogin.TextChanged += TextBoxLogin_TextChanged;
//
// customListBoxInterest
//
customListBoxInterest.Location = new Point(39, 123);
customListBoxInterest.Margin = new Padding(3, 4, 3, 4);
customListBoxInterest.Name = "customListBoxInterest";
customListBoxInterest.SelectedItem = "";
customListBoxInterest.Size = new Size(226, 157);
customListBoxInterest.TabIndex = 12;
//
// textBoxControlEmail
//
textBoxControlEmail.Location = new Point(451, 174);
textBoxControlEmail.Margin = new Padding(3, 4, 3, 4);
textBoxControlEmail.Name = "textBoxControlEmail";
textBoxControlEmail.Pattern = null;
textBoxControlEmail.Size = new Size(309, 44);
textBoxControlEmail.TabIndex = 13;
//
// textBoxAvatar
//
textBoxAvatar.Location = new Point(541, 58);
textBoxAvatar.Name = "textBoxAvatar";
textBoxAvatar.Size = new Size(125, 27);
textBoxAvatar.TabIndex = 14;
textBoxAvatar.Click += textBoxAvatar_Click;
//
// FormAccount
//
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(textBoxAvatar);
Controls.Add(textBoxControlEmail);
Controls.Add(customListBoxInterest);
Controls.Add(textBoxLogin);
Controls.Add(buttonCancel);
Controls.Add(buttonSave);
Controls.Add(labelEmail);
Controls.Add(labelAvatar);
Controls.Add(labelInterest);
Controls.Add(labelLogin);
Name = "FormAccount";
Text = "FormAccount";
Load += FormAccount_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label labelLogin;
private Label labelInterest;
private Label labelAvatar;
private Label labelEmail;
private Button buttonSave;
private Button buttonCancel;
private TextBox textBoxLogin;
private Components.CustomListBox customListBoxInterest;
private RodionovLibrary.VisualComponents.TextBoxControl textBoxControlEmail;
private TextBox textBoxAvatar;
}
}

View File

@ -0,0 +1,141 @@
using DocumentFormat.OpenXml.Vml.Office;
using PortalAccountsContracts.BindingModels;
using PortalAccountsContracts.BusinessLogicsContracts;
using PortalAccountsContracts.SearchModels;
using PortalAccountsContracts.ViewModels;
using RodionovLibrary.VisualComponents;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PortalAccountsView
{
public partial class FormAccount : Form
{
private int? _id;
private bool _isModified = false;
private readonly IAccountLogic _logic;
private readonly IInterestLogic _interestLogic;
private List<InterestViewModel> _interests;
public int Id { set { _id = value; } }
public FormAccount(IAccountLogic logic, IInterestLogic interestLogic)
{
InitializeComponent();
_logic = logic;
_interestLogic = interestLogic;
_interests = new List<InterestViewModel>();
customListBoxInterest.TextChanged += (_, _) => _isModified = true;
textBoxControlEmail.TextChanged += (_, _) => _isModified = true;
textBoxControlEmail.Pattern = @"^[a-z0-9._%+-]+\@([a-z0-9-]+\.)+[a-z]{2,4}$";
textBoxControlEmail.SetTooltipText("example@gmail.com");
}
private void FormAccount_Load(object sender, EventArgs e)
{
_interests = _interestLogic.ReadList(null) ?? throw new Exception("Не удалось получить список ролей");
customListBoxInterest.SetItems(_interests.Select(x => x.Name).ToList());
if (_id.HasValue)
{
try
{
var account = _logic.ReadElement(new AccountSearchModel { Id = _id.Value });
if (account != null)
{
textBoxLogin.Text = account.Login;
textBoxAvatar.Text = account.AvatarPath;
textBoxControlEmail.Text = account.Email;
customListBoxInterest.SelectedItem = account.InterestName;
_isModified = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (_isModified)
{
var result = MessageBox.Show(
"У вас есть несохранённые изменения. Вы действительно хотите закрыть форму?",
"Предупреждение",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning
);
if (result == DialogResult.No)
return;
}
DialogResult = DialogResult.Cancel;
Close();
}
private void buttonSave_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxLogin.Text))
{
MessageBox.Show("Заполните логин", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrEmpty(customListBoxInterest.SelectedItem))
{
MessageBox.Show("Выберите интерес", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
try
{
var model = new AccountBindingModel
{
Id = _id ?? 0,
Login = textBoxLogin.Text,
Email = textBoxControlEmail.Value,
AvatarPath = textBoxAvatar.Text,
InterestId = _interests.First(x => x.Name == customListBoxInterest.SelectedItem).Id,
};
var operationResult = _id.HasValue ? _logic.Update(model) : _logic.Create(model);
if (!operationResult)
{
throw new Exception("Ошибка при сохранении");
}
MessageBox.Show("Сохранение прошло успешно", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void TextBoxLogin_TextChanged(object sender, EventArgs e)
{
_isModified = true;
}
private void textBoxAvatar_Click(object sender, EventArgs e)
{
using (var dialog = new OpenFileDialog { Filter = "jpg|*.jpg" })
{
if (dialog.ShowDialog() == DialogResult.OK)
{
textBoxAvatar.Text = dialog.FileName.ToString();
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More