This commit is contained in:
vladimir_zinovev 2024-04-30 17:09:42 +04:00
parent ef1e3da92e
commit 33f90d6570
24 changed files with 534 additions and 4 deletions

View File

@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoRepairShopDatabaseImple
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRepairShopView", "AutoRepairShopView\AutoRepairShopView.csproj", "{11B9EC2E-9CA7-454E-8872-19AD291AC2A6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoRepairShopRestApi", "AutoRepairShopRestApi\AutoRepairShopRestApi.csproj", "{C0E3E9C4-33A3-4657-8F24-B0DCCE947F54}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -45,6 +47,10 @@ Global
{11B9EC2E-9CA7-454E-8872-19AD291AC2A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11B9EC2E-9CA7-454E-8872-19AD291AC2A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11B9EC2E-9CA7-454E-8872-19AD291AC2A6}.Release|Any CPU.Build.0 = Release|Any CPU
{C0E3E9C4-33A3-4657-8F24-B0DCCE947F54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0E3E9C4-33A3-4657-8F24-B0DCCE947F54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0E3E9C4-33A3-4657-8F24-B0DCCE947F54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C0E3E9C4-33A3-4657-8F24-B0DCCE947F54}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -12,6 +12,7 @@
<ItemGroup>
<ProjectReference Include="..\AutoRepairShopContracts\AutoRepairShopContracts.csproj" />
<ProjectReference Include="..\AutoRepairShopDatabaseImplement\AutoRepairShopDatabaseImplement.csproj" />
</ItemGroup>
</Project>

View File

@ -3,6 +3,8 @@ using AutoRepairShopContracts.BusinessLogicsContracts;
using AutoRepairShopContracts.SearchModels;
using AutoRepairShopContracts.StoragesContracts;
using AutoRepairShopContracts.ViewModels;
using AutoRepairShopDatabaseImplement.Models;
using AutoRepairShopDataModels.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@ -16,12 +18,14 @@ namespace AutoRepairShopBusinessLogic.BusinessLogic
{
private readonly ILogger _logger;
private readonly IManagerStorage _managerStorage;
private readonly IClientStorage _clientStorage;
public ManagerLogic(ILogger<ManagerLogic> logger, IManagerStorage managerStorage)
public ManagerLogic(ILogger<ManagerLogic> logger, IManagerStorage managerStorage, IClientStorage clientStorage)
{
_logger = logger;
_managerStorage = managerStorage;
}
_clientStorage = clientStorage;
}
public bool Create(ManagerBindingModel model)
{
@ -45,8 +49,25 @@ namespace AutoRepairShopBusinessLogic.BusinessLogic
}
return true;
}
public void AssignPoints(int clientId, int points)
{
var client = _clientStorage.GetElement(new ClientSearchModel { Id = clientId });
if (client != null)
{
var newPoints = new PointBindingModel
{
ClientId = clientId,
Amount = points
};
public ManagerViewModel? ReadElement(ManagerSearchModel model)
_clientStorage.AssignPoints(newPoints);
}
else
{
throw new ArgumentException($"Client with id {clientId} not found");
}
}
public ManagerViewModel? ReadElement(ManagerSearchModel model)
{
if (model == null)
{

View File

@ -12,5 +12,6 @@ namespace AutoRepairShopContracts.BindingModels
public int Id { get; set; }
public string ClientFIO { get; set; } = string.Empty;
public string JobTitle { get; set; } = string.Empty;
public int Points { get; set; }
}
}

View File

@ -9,6 +9,7 @@ namespace AutoRepairShopContracts.BindingModels
{
public class PointBindingModel : IPointModel
{
public int ClientId { get; set; }
public int Id { get; set; }
public int Amount { get; set; }
}

View File

@ -16,5 +16,6 @@ namespace AutoRepairShopContracts.BusinessLogicsContracts
bool Create(ClientBindingModel model);
bool Update(ClientBindingModel model);
bool Delete(ClientBindingModel model);
bool AssignPoints(ClientBindingModel model);
}
}

View File

@ -11,5 +11,6 @@ namespace AutoRepairShopContracts.SearchModels
public int? Id { get; set; }
public string? ClientFIO { get; set; }
public string? JobTitle { get; set; }
public int? Points { get; set; }
}
}

View File

@ -17,5 +17,6 @@ namespace AutoRepairShopContracts.StoragesContracts
ClientViewModel? Insert(ClientBindingModel model);
ClientViewModel? Update(ClientBindingModel model);
ClientViewModel? Delete(ClientBindingModel model);
ClientViewModel? AssignPoints(PointBindingModel model);
}
}

View File

@ -15,5 +15,7 @@ namespace AutoRepairShopContracts.ViewModels
public string ClientFIO { get; set; } = string.Empty;
[DisplayName("Должность")]
public string JobTitle { get; set; } = string.Empty;
[DisplayName("Баллы")]
public int Points { get; set; }
}
}

View File

@ -11,6 +11,7 @@ namespace AutoRepairShopContracts.ViewModels
public class PointViewModel : IPointModel
{
public int Id { get; set; }
public int ClientId { get; set; }
[DisplayName("Количество")]
public int Amount { get; set; }
}

View File

@ -85,5 +85,24 @@ namespace AutoRepairShopDatabaseImplement.Implements
context.SaveChanges();
return client.GetViewModel;
}
public ClientViewModel? AssignPoints(PointBindingModel model)
{
using var context = new AutoRepairShopDatabase();
var client = context.Clients.FirstOrDefault(x => x.Id == model.ClientId);
if (client == null)
{
return null;
}
var newPoint = new Point
{
ClientId = client.Id,
Amount = model.Amount
};
context.Points.Add(newPoint);
context.SaveChanges();
client.Points.Add(newPoint);
return client.GetViewModel;
}
}
}

View File

@ -18,9 +18,9 @@ namespace AutoRepairShopDatabaseImplement.Models
public string ClientFIO { get; set; }
[Required]
public string JobTitle { get; set; }
// для реализации связи многие ко многим с изделиями
[ForeignKey("ClientId")]
public virtual List<WorkClients> WorkClients { get; set; } = new();
public List<Point> Points { get; set; }
public static Client? Create(ClientBindingModel model)
{
if (model == null)

View File

@ -14,6 +14,8 @@ namespace AutoRepairShopDatabaseImplement.Models
{
public int Id { get; set; }
[Required]
public int ClientId { get; set; }
[Required]
public int Amount { get; set; }
public static Point? Create(PointBindingModel model)
{
@ -23,6 +25,7 @@ namespace AutoRepairShopDatabaseImplement.Models
}
return new Point()
{
ClientId = model.ClientId,
Id = model.Id,
Amount = model.Amount
};
@ -38,6 +41,7 @@ namespace AutoRepairShopDatabaseImplement.Models
public PointViewModel GetViewModel => new()
{
Id = Id,
ClientId = ClientId,
Amount = Amount
};
}

View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AutoRepairShopBusinessLogic\AutoRepairShopBusinessLogic.csproj" />
<ProjectReference Include="..\AutoRepairShopDatabaseImplement\AutoRepairShopDatabaseImplement.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -0,0 +1,79 @@
using AutoRepairShopContracts.BindingModels;
using AutoRepairShopContracts.BusinessLogicsContracts;
using AutoRepairShopContracts.SearchModels;
using AutoRepairShopContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace AutoRepairShopRestApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class ClientController : ControllerBase
{
private readonly ILogger _logger;
private readonly IClientLogic _logic;
public ClientController(IClientLogic logic, ILogger<ClientController> logger)
{
_logger = logger;
_logic = logic;
}
[HttpGet]
public void GetClientInfo(int id)
{
try
{
var clientInfo = _logic.ReadElement(new ClientSearchModel { Id = id });
if (clientInfo != null)
{
Response.WriteAsync(clientInfo.ToString());
}
else
{
Response.StatusCode = 404;
Response.WriteAsync($"Client with ID {id} not found");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching client information");
}
}
[HttpPost]
public void CreateClient(ClientBindingModel model)
{
try
{
_logic.Create(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create client");
}
}
[HttpPost]
public void AssignPointsToClient(ClientBindingModel model)
{
try
{
if (_logic.AssignPoints(model))
{
Response.WriteAsync($"Successfully assigned {model.Points} points to client with ID {model.Id}");
}
else
{
Response.StatusCode = 400;
Response.WriteAsync($"Failed to assign points to client with ID {model.Id}");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to assign points to client");
}
}
}
}

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc;
namespace AutoRepairShopRestApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class MainController : ControllerBase
{
[HttpGet]
public IActionResult Index()
{
return Ok("Welcome to the main page");
}
}
}

View File

@ -0,0 +1,66 @@
using AutoRepairShopContracts.BindingModels;
using AutoRepairShopContracts.BusinessLogicsContracts;
using AutoRepairShopContracts.SearchModels;
using AutoRepairShopContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace AutoRepairShopRestApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class ManagerController : ControllerBase
{
private readonly ILogger _logger;
private readonly IManagerLogic _logic;
public ManagerController(IManagerLogic logic, ILogger<ManagerController> logger)
{
_logger = logger;
_logic = logic;
}
[HttpGet]
public ManagerViewModel? Login(string login, string password)
{
try
{
return _logic.ReadElement(new ManagerSearchModel
{
Login = login,
Password = password
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка входа в систему");
throw;
}
}
[HttpPost]
public void Register(ManagerBindingModel model)
{
try
{
_logic.Create(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка регистрации");
throw;
}
}
[HttpPost]
public void UpdateData(ManagerBindingModel model)
{
try
{
_logic.Update(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка обновления данных");
throw;
}
}
}
}

View File

@ -0,0 +1,50 @@
using AutoRepairShopBusinessLogic.BusinessLogic;
using AutoRepairShopContracts.BusinessLogicsContracts;
using AutoRepairShopContracts.StoragesContracts;
using AutoRepairShopDatabaseImplement.Implements;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Logging.AddLog4Net(@"log4net.config");
// Add services to the container.
builder.Services.AddTransient<IClientStorage, ClientStorage>();
builder.Services.AddTransient<IManagerStorage, ManagerStorage>();
builder.Services.AddTransient<IPointStorage, PointStorage>();
builder.Services.AddTransient<ITaskStorage, TaskStorage>();
builder.Services.AddTransient<IWorkStorage, WorkStorage>();
builder.Services.AddTransient<IManagerLogic, ManagerLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<IPointLogic, PointLogic>();
builder.Services.AddTransient<ITaskLogic, TaskLogic>();
builder.Services.AddTransient<IWorkLogic, WorkLogic>();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at
https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "AutoRepairShopRestApi",
Version
= "v1"
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json",
"AutoRepairShopRestApi v1"));
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
//
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AutoRepairShopRestApi.Properties {
using System;
/// <summary>
/// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д.
/// </summary>
// Этот класс создан автоматически классом StronglyTypedResourceBuilder
// с помощью такого средства, как ResGen или Visual Studio.
// Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen
// с параметром /str или перестройте свой проект VS.
[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>
/// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом.
/// </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("AutoRepairShopRestApi.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Перезаписывает свойство CurrentUICulture текущего потока для всех
/// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
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">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</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.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:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<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" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</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>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:27887",
"sslPort": 44314
}
},
"profiles": {
"AutoRepairShopRestApi": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7143;http://localhost:5267",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="c:/temp/AbstractShopRestApi.log" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %5level %logger.%method [%line] - MESSAGE: %message%newline %exception" />
</layout>
</appender>
<root>
<level value="TRACE" />
<appender-ref ref="RollingFile" />
</root>
</log4net>