From 3c2b7ea89b5105048b6e77cac245f201d7603280 Mon Sep 17 00:00:00 2001
From: rexx07 <56883674+rexx07@users.noreply.github.com>
Date: Wed, 1 Mar 2023 11:28:45 -0500
Subject: [PATCH 1/5] initial commit
---
.idea/.idea.BankingSoftware/.idea/.gitignore | 13 ++
.../.idea.BankingSoftware/.idea/encodings.xml | 4 +
.../.idea/indexLayout.xml | 8 ++
.idea/.idea.BankingSoftware/.idea/vcs.xml | 6 +
BankingSoftware.sln | 16 +++
BankingSoftware/BankingSoftware.csproj | 16 +++
BankingSoftware/Common/AddSymbol.cs | 26 ++++
BankingSoftware/Common/Hash.cs | 28 ++++
BankingSoftware/Common/VerifyInput.cs | 129 ++++++++++++++++++
BankingSoftware/Common/WriteFile.cs | 24 ++++
BankingSoftware/Modules/AccountModule.cs | 129 ++++++++++++++++++
BankingSoftware/Modules/AuthModule.cs | 41 ++++++
BankingSoftware/Modules/SignupModule.cs | 93 +++++++++++++
BankingSoftware/Program.cs | 111 +++++++++++++++
.../5FE5F846BD5D98FFF20F1384D0DFC710.txt | 5 +
.../2947CB1B92BB13C8F373E78C76FCA765.txt | 8 ++
16 files changed, 657 insertions(+)
create mode 100644 .idea/.idea.BankingSoftware/.idea/.gitignore
create mode 100644 .idea/.idea.BankingSoftware/.idea/encodings.xml
create mode 100644 .idea/.idea.BankingSoftware/.idea/indexLayout.xml
create mode 100644 .idea/.idea.BankingSoftware/.idea/vcs.xml
create mode 100644 BankingSoftware.sln
create mode 100644 BankingSoftware/BankingSoftware.csproj
create mode 100644 BankingSoftware/Common/AddSymbol.cs
create mode 100644 BankingSoftware/Common/Hash.cs
create mode 100644 BankingSoftware/Common/VerifyInput.cs
create mode 100644 BankingSoftware/Common/WriteFile.cs
create mode 100644 BankingSoftware/Modules/AccountModule.cs
create mode 100644 BankingSoftware/Modules/AuthModule.cs
create mode 100644 BankingSoftware/Modules/SignupModule.cs
create mode 100644 BankingSoftware/Program.cs
create mode 100644 BankingSoftware/Storage/Accounts/5FE5F846BD5D98FFF20F1384D0DFC710.txt
create mode 100644 BankingSoftware/Storage/Users/2947CB1B92BB13C8F373E78C76FCA765.txt
diff --git a/.idea/.idea.BankingSoftware/.idea/.gitignore b/.idea/.idea.BankingSoftware/.idea/.gitignore
new file mode 100644
index 0000000..794932b
--- /dev/null
+++ b/.idea/.idea.BankingSoftware/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/contentModel.xml
+/projectSettingsUpdater.xml
+/.idea.BankingSoftware.iml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.BankingSoftware/.idea/encodings.xml b/.idea/.idea.BankingSoftware/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.BankingSoftware/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.BankingSoftware/.idea/indexLayout.xml b/.idea/.idea.BankingSoftware/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.BankingSoftware/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.BankingSoftware/.idea/vcs.xml b/.idea/.idea.BankingSoftware/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.BankingSoftware/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BankingSoftware.sln b/BankingSoftware.sln
new file mode 100644
index 0000000..4792473
--- /dev/null
+++ b/BankingSoftware.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankingSoftware", "BankingSoftware\BankingSoftware.csproj", "{335BF223-9311-4DF9-A534-4B3831D2279E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {335BF223-9311-4DF9-A534-4B3831D2279E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {335BF223-9311-4DF9-A534-4B3831D2279E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {335BF223-9311-4DF9-A534-4B3831D2279E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {335BF223-9311-4DF9-A534-4B3831D2279E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/BankingSoftware/BankingSoftware.csproj b/BankingSoftware/BankingSoftware.csproj
new file mode 100644
index 0000000..16660e4
--- /dev/null
+++ b/BankingSoftware/BankingSoftware.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net7.0
+ disable
+ enable
+ BankingSoftware
+
+
+
+
+
+
+
+
diff --git a/BankingSoftware/Common/AddSymbol.cs b/BankingSoftware/Common/AddSymbol.cs
new file mode 100644
index 0000000..1fc6910
--- /dev/null
+++ b/BankingSoftware/Common/AddSymbol.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+
+namespace BankingSoftware.Common;
+
+public static class AddSymbol
+{
+ public static void AddBreakLine(int symbolLength = 80, string symbol = "-")
+ {
+ for (var i = 0; i < symbolLength; i++)
+ {
+ Console.Write(symbol);
+ }
+ Console.WriteLine("");
+ }
+
+ public static void AddBreakLines(int symbolLength = 80, int lineLength = 3, string symbol = "-")
+ {
+ for (int i = 0; i < lineLength; i++)
+ {
+ AddBreakLine(symbolLength, symbol);
+ }
+
+ Console.WriteLine("\n");
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Common/Hash.cs b/BankingSoftware/Common/Hash.cs
new file mode 100644
index 0000000..f118b5c
--- /dev/null
+++ b/BankingSoftware/Common/Hash.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace BankingSoftware.Common;
+
+public class Hash
+{
+ const int keySize = 16;
+ const int iterations = 350000;
+ HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256;
+
+ public string HashValues(string[] values)
+ {
+ var joinedValues = string.Join("", values);
+
+ var salt = new UTF8Encoding(true).GetBytes(joinedValues);
+
+ var hash = Rfc2898DeriveBytes.Pbkdf2(
+ Encoding.UTF8.GetBytes(joinedValues),
+ salt,
+ iterations,
+ hashAlgorithm,
+ keySize);
+
+ return Convert.ToHexString(hash);
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Common/VerifyInput.cs b/BankingSoftware/Common/VerifyInput.cs
new file mode 100644
index 0000000..66d9a50
--- /dev/null
+++ b/BankingSoftware/Common/VerifyInput.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace BankingSoftware.Common;
+
+public static partial class VerifyInput
+{
+ public static string VerifyForStringOnly(string input)
+ {
+ while (
+ string.IsNullOrEmpty(input)
+ || string.IsNullOrWhiteSpace(input)
+ || input.Any(char.IsNumber)
+ || input.Any(c =>
+ {
+ char.IsNumber(c);
+ char.IsSymbol(c);
+ char.IsPunctuation(c);
+ char.IsSeparator(c);
+
+ return false;
+ })
+ )
+ {
+ Console.WriteLine("Input must not contain any number or symbol");
+ Console.Write("Please input new value: ");
+ input = Console.ReadLine();
+ }
+
+ Console.WriteLine("Input is valid");
+ return input;
+ }
+
+ public static string VerifyForStringAndNumber(string stringNumber)
+ {
+ while (
+ string.IsNullOrEmpty(stringNumber)
+ || string.IsNullOrWhiteSpace(stringNumber)
+ || stringNumber.Any(c =>
+ {
+ char.IsLetter(c);
+ char.IsPunctuation(c);
+ char.IsSymbol(c);
+
+ return false;
+ })
+ )
+ {
+ Console.WriteLine("Input must not contain any number or symbol");
+ Console.Write("Please input new value: ");
+ stringNumber = Console.ReadLine();
+ }
+
+ Console.WriteLine("Input is valid");
+ return stringNumber;
+ }
+
+ public static int VerifyNumber(int number)
+ {
+ while (
+ string.IsNullOrEmpty(number.ToString())
+ || string.IsNullOrWhiteSpace(number.ToString())
+ || number.ToString().Any(c =>
+ {
+ char.IsSymbol(c);
+ char.IsPunctuation(c);
+ char.IsLetter(c);
+
+
+ return false;
+ })
+ )
+ {
+ Console.WriteLine("Input must not contain any letter or symbol");
+ Console.Write("Please input your value: ");
+ number = int.Parse(Console.ReadLine());
+ }
+
+ Console.WriteLine("Number is valid");
+ return number;
+ }
+
+ public static string VerifyPassword(string password)
+ {
+ while (
+ string.IsNullOrEmpty(password)
+ || string.IsNullOrWhiteSpace(password)
+ )
+ {
+ Console.WriteLine("Input must not contain any space");
+ Console.Write("Please input new value: ");
+ password = Console.ReadLine();
+ }
+
+ Console.WriteLine("Password is valid");
+ return password;
+ }
+
+ [GeneratedRegex("^\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$")]
+ private static partial Regex MyRegex();
+
+ public static string VerifyPhoneNumber(string phoneNumber)
+ {
+ while (!MyRegex().IsMatch(phoneNumber))
+ {
+ Console.WriteLine("Input must not contain any letter or symbol");
+ Console.Write("Please input new value: ");
+ phoneNumber = Console.ReadLine();
+ }
+
+ Console.WriteLine("Phone number is valid");
+ return phoneNumber;
+ }
+
+ public static string VerifyEmail(string email)
+ {
+ string regex = @"^[^@\s]+@[^@\s]+\.(com|net|org|gov)$";
+
+ while (!Regex.IsMatch(email, regex, RegexOptions.IgnoreCase))
+ {
+ Console.Write("Input a valid email: ");
+ email = Console.ReadLine();
+ }
+
+ Console.WriteLine("Email is valid.");
+ return email;
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Common/WriteFile.cs b/BankingSoftware/Common/WriteFile.cs
new file mode 100644
index 0000000..73df185
--- /dev/null
+++ b/BankingSoftware/Common/WriteFile.cs
@@ -0,0 +1,24 @@
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace BankingSoftware.Common;
+
+public static class WriteFile
+{
+ public static void WriteLine(string lineText, string fileName)
+ {
+ using var fs = File.AppendText(fileName);
+ fs.Write(lineText);
+ }
+
+ public static void WriteLines(string[] linesTexts, string fileName)
+ {
+ using var fs = File.OpenWrite(fileName);
+ for (int i = 0; i < linesTexts.Length; i++)
+ {
+ byte[] info = new UTF8Encoding(true).GetBytes(linesTexts[i] + "\n");
+ fs.Write(info, 0, info.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Modules/AccountModule.cs b/BankingSoftware/Modules/AccountModule.cs
new file mode 100644
index 0000000..42a8e28
--- /dev/null
+++ b/BankingSoftware/Modules/AccountModule.cs
@@ -0,0 +1,129 @@
+using System;
+using System.IO;
+using BankingSoftware.Common;
+
+namespace BankingSoftware.Modules;
+
+public class AccountModule
+{
+ private static string GetAccountFile(in string userLogin, string accountStoragePath)
+ {
+ var charFileName = userLogin.Split();
+ var accountFileName = new Hash().HashValues(charFileName) ;
+ var accountFilenameWithPath = accountStoragePath + accountFileName + ".txt";
+
+ return accountFilenameWithPath;
+ }
+
+ private static string[] GetAccountSummary(string accountFilename)
+ {
+ var accountInfo = File.ReadAllLines(accountFilename);
+
+ return accountInfo;
+ }
+
+ public static void Deposit(in string userLogin, string accountStoragePath)
+ {
+ var accountFilename = GetAccountFile(userLogin, accountStoragePath);
+
+ var accountInfo = GetAccountSummary(accountFilename);
+ foreach (var info in accountInfo)
+ {
+ Console.WriteLine(info);
+ }
+
+ Console.Write("Please enter the amount you want to deposit: ");
+ var depositAmount = int.Parse(Console.ReadLine());
+
+ while (depositAmount is string && depositAmount < 0 )
+ {
+ depositAmount = int.Parse(Console.ReadLine());
+ }
+
+ var depositAmountLine = accountInfo[2].Split(": $");
+ var depositTimeLine = accountInfo[3].Split(": ");
+ depositAmountLine[1] = depositAmount.ToString();
+ depositTimeLine[1] = DateTime.Now.ToString();
+
+ accountInfo[2] = string.Join(": ", depositAmountLine);
+ accountInfo[3] = string.Join(": ", depositTimeLine);
+
+ var totalLine = accountInfo[4].Split(": $");
+
+ var totalAmount = int.Parse(totalLine[1]) + depositAmount;
+ totalLine[1] = totalAmount.ToString();
+ accountInfo[4] = string.Join(": $", totalLine);
+
+ Console.WriteLine("You've deposited ${0} to your account", depositAmount);
+
+ Console.WriteLine("\nYour total amount is ${0}", totalAmount);
+
+ WriteFile.WriteLines(accountInfo, accountFilename);
+ }
+
+ public static void Withdraw(in string userLogin, string accountStoragePath)
+ {
+ var accountFilename = GetAccountFile(userLogin, accountStoragePath);
+
+ var accountInfo = GetAccountSummary(accountFilename);
+ var totalLine = accountInfo[4].Split(": $");
+
+ Console.Write("Please enter the amount you want to withdraw: ");
+ var withdrawAmount = int.Parse(Console.ReadLine());
+ var currentTotal = int.Parse(totalLine[1]);
+ var finalTotalAmount = currentTotal - withdrawAmount;
+
+ while (withdrawAmount is string && withdrawAmount < 0)
+ {
+ Console.WriteLine("Your withdraw amount should be greater than Zero");
+ withdrawAmount = int.Parse(Console.ReadLine());
+ finalTotalAmount = currentTotal - withdrawAmount;
+ }
+
+ if (finalTotalAmount < 0)
+ {
+ Console.WriteLine("Insufficient balance.");
+ }
+ else
+ {
+ var withdrawAmountLine = accountInfo[0].Split(": ");
+ var withdrawTimeLine = accountInfo[1].Split(": ");
+ withdrawAmountLine[1] = withdrawAmount.ToString();
+ withdrawTimeLine[1] = DateTime.Now.ToString();
+
+ accountInfo[0] = string.Join(": ", withdrawAmountLine);
+ accountInfo[1] = string.Join(": ", withdrawTimeLine);
+
+ totalLine[1] = finalTotalAmount.ToString();
+ accountInfo[4] = string.Join(": $", totalLine);
+
+ Console.WriteLine("You've withdrawn ${0} from your account", withdrawAmount);
+
+ Console.WriteLine("\nYour have ${0} left in your account", finalTotalAmount);
+
+ WriteFile.WriteLines(accountInfo, accountFilename);
+ }
+
+ }
+
+ public static void ViewAccountBalance(in string userLogin, string accountStoragePath)
+ {
+ var accountFilename = GetAccountFile(userLogin, accountStoragePath);
+
+ var accountBalance = GetAccountSummary(accountFilename)[4];
+
+ Console.WriteLine("Your account balance is {0}", accountBalance);
+ }
+
+ public static void ViewAccountSummary(in string userLogin, string accountStoragePath)
+ {
+ var accountFilename = GetAccountFile(userLogin, accountStoragePath);
+
+ var accountInfo = GetAccountSummary(accountFilename);
+
+ foreach (var info in accountInfo)
+ {
+ Console.WriteLine(info);
+ }
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Modules/AuthModule.cs b/BankingSoftware/Modules/AuthModule.cs
new file mode 100644
index 0000000..a3a3723
--- /dev/null
+++ b/BankingSoftware/Modules/AuthModule.cs
@@ -0,0 +1,41 @@
+using System;
+using System.IO;
+using BankingSoftware.Common;
+
+namespace BankingSoftware.Modules;
+
+public static class AuthModule
+{
+ public static string SignIn(string userStoragePath)
+ {
+ Console.Write("Please enter your username: ");
+ var username = Console.ReadLine();
+
+ Console.Write("Please enter your password: ");
+ var password = Console.ReadLine();
+ var hashedPassword = new Hash().HashValues(password.Split());
+
+ var userLogin = new Hash().HashValues(new string[] { username, hashedPassword });
+ var hashedUsername = new Hash().HashValues(username.Split());
+ var userExist = File.Exists(userStoragePath + hashedUsername + ".txt");
+
+ while(!userExist)
+ {
+ Console.WriteLine("Incorrect username or password, please try again");
+ Console.Write("Please enter your username: ");
+ username = Console.ReadLine();
+
+ Console.Write("Please enter your password: ");
+ password = Console.ReadLine();
+ hashedPassword = new Hash().HashValues(password.Split());
+
+ userLogin = new Hash().HashValues(new string[] { username, hashedPassword });
+ hashedUsername = new Hash().HashValues(username.Split());
+ userExist = File.Exists(userStoragePath + hashedUsername + ".txt");
+ }
+
+ Console.WriteLine("Welcome {0}", username);
+
+ return userLogin;
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Modules/SignupModule.cs b/BankingSoftware/Modules/SignupModule.cs
new file mode 100644
index 0000000..76ee926
--- /dev/null
+++ b/BankingSoftware/Modules/SignupModule.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Linq;
+using System.Text;
+using BankingSoftware.Common;
+
+namespace BankingSoftware.Modules;
+
+public class SignupModule
+{
+ //const string StoragePath =
+
+ public static string Signup(string userStoragePath)
+ {
+ string[] userKeys = { "First Name: ", "Last Name: ", "Email: ", "Username: ", "Age: ", "Phone Number: ",
+ "HashedPassword: " };
+ var userValues = new string[userKeys.Length + 1];
+
+ Console.WriteLine("Please answer the questions below to signup...");
+ AddSymbol.AddBreakLine(symbol:" ");
+
+ Console.Write("Enter your first name: ");
+ var firstName = Console.ReadLine();
+ VerifyInput.VerifyForStringOnly(firstName);
+ userValues[0] = (userKeys[0] + firstName);
+ AddSymbol.AddBreakLine();
+
+ Console.Write("Enter your last name: ");
+ var lastName = Console.ReadLine();
+ VerifyInput.VerifyForStringOnly(lastName);
+ userValues[1] = (userKeys[1] + lastName);
+ AddSymbol.AddBreakLine();
+
+ Console.Write("Enter your email: ");
+ var email = Console.ReadLine();
+ email = VerifyInput.VerifyEmail(email);
+ userValues[2] = (userKeys[2] + email);
+ AddSymbol.AddBreakLine();
+
+ Console.Write("Enter your username: ");
+ var username = Console.ReadLine();
+ username = VerifyInput.VerifyForStringAndNumber(username);
+ userValues[3] = (userKeys[3] + username);
+ AddSymbol.AddBreakLine();
+
+ Console.Write("Enter your age: ");
+ var age = int.Parse(Console.ReadLine());
+ age = VerifyInput.VerifyNumber(age);
+ while(age < 18 || age > 100)
+ {
+ Console.WriteLine("Age should be between 18 and 100");
+ Console.Write("Input new value");
+ Console.ReadLine();
+
+ age = int.Parse(Console.ReadLine());
+ VerifyInput.VerifyNumber(age);
+ }
+ userValues[4] = (userKeys[4] + age);
+ AddSymbol.AddBreakLine();
+
+ Console.Write("Enter your phone number: ");
+ var phoneNumber = Console.ReadLine();
+ phoneNumber = VerifyInput.VerifyPhoneNumber(phoneNumber);
+ userValues[5] = (userKeys[5] + phoneNumber);
+ AddSymbol.AddBreakLine();
+
+ Console.Write("Enter your password: ");
+ var password = Console.ReadLine();
+ password = VerifyInput.VerifyPassword(password);
+ var hashedPassword = new Hash().HashValues(password.Split());
+ userValues[6] = (userKeys[6] + hashedPassword);
+ AddSymbol.AddBreakLines(lineLength: 2);
+
+ var hashedUsername = new Hash().HashValues(username.Split());
+ userStoragePath += "\\" + hashedUsername + ".txt";
+ WriteFile.WriteLines(userValues, userStoragePath);
+
+ var credentials = new Hash().HashValues(new[] { username, hashedPassword });
+
+ return credentials;
+ }
+
+ public static void CreateAccount(in string userLogin, string accountStoragePath)
+ {
+ string[] accountValues = { "Last withdrawal amount: $0", "Last withdrawal time: ", "Last deposit amount: $0",
+ "Last deposit time: " , "Total: $0"};
+
+ var charFileName = userLogin.Split();
+ var hashedFileName = new Hash().HashValues(charFileName) ;
+
+ var accountFilename = accountStoragePath + hashedFileName + ".txt";
+ WriteFile.WriteLines(accountValues, accountFilename);
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Program.cs b/BankingSoftware/Program.cs
new file mode 100644
index 0000000..c178dd9
--- /dev/null
+++ b/BankingSoftware/Program.cs
@@ -0,0 +1,111 @@
+using System;
+using BankingSoftware.Common;
+using BankingSoftware.Modules;
+
+namespace BankingSoftware;
+
+class Program
+{
+ const string userStoragePath = @"C:\Users\rexxr\Documents\projectss\CodeBenders\BankingSoftware\Storage\Users\";
+
+ const string accountStoragePath =
+ @"C:\Users\rexxr\Documents\projectss\CodeBenders\BankingSoftware\Storage\Accounts\";
+
+ public static void Auth(out string userLogin)
+ {
+ userLogin = "";
+ Console.WriteLine("\nWelcome to our console banking app");
+ AddSymbol.AddBreakLines(symbol: "*");
+
+ Console.WriteLine("Please login or signup. \n");
+ Console.WriteLine("Press 1 to login or 2 to signup");
+ Console.Write(">>>>> ");
+ var loginSignup = int.Parse(Console.ReadLine());
+ Console.WriteLine("\n");
+
+ while (loginSignup is string || loginSignup > 2)
+ {
+ Console.WriteLine("Input the correct value...");
+ Console.Write(">>>>> ");
+ loginSignup = int.Parse(Console.ReadLine());
+ }
+ switch (loginSignup)
+ {
+ case 1:
+ userLogin = AuthModule.SignIn(userStoragePath);
+ break;
+ case 2:
+ userLogin = SignupModule.Signup(userStoragePath);
+ SignupModule.CreateAccount(userLogin, accountStoragePath);
+ break;
+
+ }
+
+ AddSymbol.AddBreakLine();
+ }
+
+ public static void Account(in string userLogin)
+ {
+ Console.WriteLine("What action do you want to perform");
+ Console.WriteLine("Press 1 to VIEW ACCOUNT SUMMARY");
+ Console.WriteLine("Press 2 to VIEW BALANCE");
+ Console.WriteLine("Press 3 to DEPOSIT");
+ Console.WriteLine("Press 4 to WITHDRAW");
+
+ Console.Write(">>>>> ");
+ var action = int.Parse(Console.ReadLine());
+
+ switch (action)
+ {
+ case 1:
+ AccountModule.ViewAccountSummary(in userLogin, accountStoragePath);
+ break;
+ case 2:
+ AccountModule.ViewAccountBalance(in userLogin, accountStoragePath);
+ break;
+ case 3:
+ AccountModule.Deposit(in userLogin, accountStoragePath);
+ break;
+ case 4:
+ AccountModule.Withdraw(in userLogin, accountStoragePath);
+ break;
+ default:
+ Console.WriteLine("Input the correct value");
+ break;
+ }
+
+ Console.WriteLine("Do you want to perform another transaction");
+ Console.WriteLine("............ Press 1 to continue");
+ Console.WriteLine("............ Press 2 to quit");
+ Console.Write(">>>>> ");
+ var anotherAction = int.Parse(Console.ReadLine());
+
+ while (anotherAction > 2)
+ {
+ Console.WriteLine("Please input the correct value.");
+ Console.Write(">>>>> ");
+ anotherAction = int.Parse(Console.ReadLine());
+ }
+ while (anotherAction == 1)
+ {
+ Account(in userLogin);
+ Console.Write(">>>>> ");
+ anotherAction = int.Parse(Console.ReadLine());
+ }
+
+ if (anotherAction == 2)
+ {
+ Console.WriteLine("Thank you for banking with us...");
+ Console.WriteLine("Goodbye.");
+ }
+
+ AddSymbol.AddBreakLines(symbol: "*");
+ }
+
+ static void Main()
+ {
+ Auth(out var userLogin);
+
+ Account(in userLogin);
+ }
+}
\ No newline at end of file
diff --git a/BankingSoftware/Storage/Accounts/5FE5F846BD5D98FFF20F1384D0DFC710.txt b/BankingSoftware/Storage/Accounts/5FE5F846BD5D98FFF20F1384D0DFC710.txt
new file mode 100644
index 0000000..9f6b71d
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/5FE5F846BD5D98FFF20F1384D0DFC710.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: 20000
+Last withdrawal time: 3/1/2023 10:02:54 AM
+Last deposit amount: 90000
+Last deposit time: 3/1/2023 10:02:43 AM
+Total: $70000
diff --git a/BankingSoftware/Storage/Users/2947CB1B92BB13C8F373E78C76FCA765.txt b/BankingSoftware/Storage/Users/2947CB1B92BB13C8F373E78C76FCA765.txt
new file mode 100644
index 0000000..8cb0584
--- /dev/null
+++ b/BankingSoftware/Storage/Users/2947CB1B92BB13C8F373E78C76FCA765.txt
@@ -0,0 +1,8 @@
+First Name: Ade
+Last Name: Bendel
+Email: ade@bendel.com
+Username: ade
+Age: 78
+Phone Number: 9834563247
+HashedPassword: D84BA9FED904447C1BE566032AF633CD
+
From fc725871f14a686d23297c47df93b7ae69160c1b Mon Sep 17 00:00:00 2001
From: rexx07 <56883674+rexx07@users.noreply.github.com>
Date: Thu, 2 Mar 2023 04:25:16 -0500
Subject: [PATCH 2/5] amends
---
.gitignore | 3 +++
.idea/.idea.BankingSoftware/.idea/.gitignore | 13 -------------
.idea/.idea.BankingSoftware/.idea/encodings.xml | 4 ----
.idea/.idea.BankingSoftware/.idea/indexLayout.xml | 8 --------
.idea/.idea.BankingSoftware/.idea/vcs.xml | 6 ------
BankingSoftware/Program.cs | 8 +++++---
BankingSoftware.sln => CodeBenders.sln | 0
7 files changed, 8 insertions(+), 34 deletions(-)
delete mode 100644 .idea/.idea.BankingSoftware/.idea/.gitignore
delete mode 100644 .idea/.idea.BankingSoftware/.idea/encodings.xml
delete mode 100644 .idea/.idea.BankingSoftware/.idea/indexLayout.xml
delete mode 100644 .idea/.idea.BankingSoftware/.idea/vcs.xml
rename BankingSoftware.sln => CodeBenders.sln (100%)
diff --git a/.gitignore b/.gitignore
index dfcfd56..30fbdce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,9 @@
*.userosscache
*.sln.docstates
+# directories
+.idea
+
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
diff --git a/.idea/.idea.BankingSoftware/.idea/.gitignore b/.idea/.idea.BankingSoftware/.idea/.gitignore
deleted file mode 100644
index 794932b..0000000
--- a/.idea/.idea.BankingSoftware/.idea/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Rider ignored files
-/modules.xml
-/contentModel.xml
-/projectSettingsUpdater.xml
-/.idea.BankingSoftware.iml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/.idea.BankingSoftware/.idea/encodings.xml b/.idea/.idea.BankingSoftware/.idea/encodings.xml
deleted file mode 100644
index df87cf9..0000000
--- a/.idea/.idea.BankingSoftware/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/.idea.BankingSoftware/.idea/indexLayout.xml b/.idea/.idea.BankingSoftware/.idea/indexLayout.xml
deleted file mode 100644
index 7b08163..0000000
--- a/.idea/.idea.BankingSoftware/.idea/indexLayout.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/.idea.BankingSoftware/.idea/vcs.xml b/.idea/.idea.BankingSoftware/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/.idea.BankingSoftware/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BankingSoftware/Program.cs b/BankingSoftware/Program.cs
index c178dd9..1241f82 100644
--- a/BankingSoftware/Program.cs
+++ b/BankingSoftware/Program.cs
@@ -8,9 +8,8 @@ class Program
{
const string userStoragePath = @"C:\Users\rexxr\Documents\projectss\CodeBenders\BankingSoftware\Storage\Users\";
- const string accountStoragePath =
- @"C:\Users\rexxr\Documents\projectss\CodeBenders\BankingSoftware\Storage\Accounts\";
-
+ const string accountStoragePath = @"C:\Users\rexxr\Documents\projectss\CodeBenders\BankingSoftware\Storage\Accounts\";
+
public static void Auth(out string userLogin)
{
userLogin = "";
@@ -104,6 +103,9 @@ public static void Account(in string userLogin)
static void Main()
{
+ Console.WriteLine(userStoragePath);
+ Console.WriteLine(accountStoragePath);
+
Auth(out var userLogin);
Account(in userLogin);
diff --git a/BankingSoftware.sln b/CodeBenders.sln
similarity index 100%
rename from BankingSoftware.sln
rename to CodeBenders.sln
From fbcf1813699a4fe26d762fb139e778fa525c0598 Mon Sep 17 00:00:00 2001
From: SunkanmiKingin <126165259+SunkanmiKingin@users.noreply.github.com>
Date: Thu, 2 Mar 2023 04:30:09 -0500
Subject: [PATCH 3/5] Delete .idea/.idea.BankingSoftware/.idea directory
---
.idea/.idea.BankingSoftware/.idea/.gitignore | 13 -------------
.idea/.idea.BankingSoftware/.idea/encodings.xml | 4 ----
.idea/.idea.BankingSoftware/.idea/indexLayout.xml | 8 --------
.idea/.idea.BankingSoftware/.idea/vcs.xml | 6 ------
4 files changed, 31 deletions(-)
delete mode 100644 .idea/.idea.BankingSoftware/.idea/.gitignore
delete mode 100644 .idea/.idea.BankingSoftware/.idea/encodings.xml
delete mode 100644 .idea/.idea.BankingSoftware/.idea/indexLayout.xml
delete mode 100644 .idea/.idea.BankingSoftware/.idea/vcs.xml
diff --git a/.idea/.idea.BankingSoftware/.idea/.gitignore b/.idea/.idea.BankingSoftware/.idea/.gitignore
deleted file mode 100644
index 794932b..0000000
--- a/.idea/.idea.BankingSoftware/.idea/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Rider ignored files
-/modules.xml
-/contentModel.xml
-/projectSettingsUpdater.xml
-/.idea.BankingSoftware.iml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/.idea.BankingSoftware/.idea/encodings.xml b/.idea/.idea.BankingSoftware/.idea/encodings.xml
deleted file mode 100644
index df87cf9..0000000
--- a/.idea/.idea.BankingSoftware/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/.idea.BankingSoftware/.idea/indexLayout.xml b/.idea/.idea.BankingSoftware/.idea/indexLayout.xml
deleted file mode 100644
index 7b08163..0000000
--- a/.idea/.idea.BankingSoftware/.idea/indexLayout.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/.idea.BankingSoftware/.idea/vcs.xml b/.idea/.idea.BankingSoftware/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/.idea.BankingSoftware/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
From 25c7703f8cb55c802884bad5202afb28e583191d Mon Sep 17 00:00:00 2001
From: sunkanmi
Date: Sat, 11 Mar 2023 10:07:35 -0500
Subject: [PATCH 4/5] libraryManagementAdded
---
LibraryManagementApp/ApiResponse/ApiResult.cs | 152 ++++++++++++++++++
.../RepositoryContracts/IAuthorRepository.cs | 8 +
.../RepositoryContracts/IBookRepository.cs | 8 +
.../ICategoryRepository.cs | 8 +
.../IPublisherRepository.cs | 8 +
.../RepositoryContracts/IRepositoryBase.cs | 15 ++
.../RepositoryContracts/IUnitOfWork.cs | 11 ++
.../Controllers/AuthorController.cs | 122 ++++++++++++++
.../Controllers/BookController.cs | 134 +++++++++++++++
.../Controllers/CategoryController.cs | 113 +++++++++++++
LibraryManagementApp/Domain/BaseEntity.cs | 23 +++
LibraryManagementApp/Dtos/AuthorDto.cs | 11 ++
LibraryManagementApp/Dtos/BookDto.cs | 16 ++
LibraryManagementApp/Dtos/CategoryDto.cs | 8 +
LibraryManagementApp/Dtos/PublisherDto.cs | 10 ++
.../Persistence/ApplicationDbContext.cs | 26 +++
.../Configurations/AuthorConfiguration.cs | 15 ++
.../Configurations/BookConfiguration.cs | 17 ++
.../Configurations/CategoryConfiguration.cs | 16 ++
.../Configurations/PublisherConfiguration.cs | 16 ++
.../Repository/AuthorRepository.cs | 11 ++
.../Persistence/Repository/BookRepository.cs | 11 ++
.../Repository/CategoryRepository.cs | 11 ++
.../Repository/PublisherRepository.cs | 11 ++
.../Persistence/Repository/RepositoryBase.cs | 45 ++++++
.../Persistence/Repository/UnitOfWork.cs | 28 ++++
26 files changed, 854 insertions(+)
create mode 100644 LibraryManagementApp/ApiResponse/ApiResult.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs
create mode 100644 LibraryManagementApp/Controllers/AuthorController.cs
create mode 100644 LibraryManagementApp/Controllers/BookController.cs
create mode 100644 LibraryManagementApp/Controllers/CategoryController.cs
create mode 100644 LibraryManagementApp/Domain/BaseEntity.cs
create mode 100644 LibraryManagementApp/Dtos/AuthorDto.cs
create mode 100644 LibraryManagementApp/Dtos/BookDto.cs
create mode 100644 LibraryManagementApp/Dtos/CategoryDto.cs
create mode 100644 LibraryManagementApp/Dtos/PublisherDto.cs
create mode 100644 LibraryManagementApp/Persistence/ApplicationDbContext.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/AuthorConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/BookConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/CategoryConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/PublisherConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/AuthorRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/BookRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/CategoryRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/PublisherRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/RepositoryBase.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/UnitOfWork.cs
diff --git a/LibraryManagementApp/ApiResponse/ApiResult.cs b/LibraryManagementApp/ApiResponse/ApiResult.cs
new file mode 100644
index 0000000..e91825b
--- /dev/null
+++ b/LibraryManagementApp/ApiResponse/ApiResult.cs
@@ -0,0 +1,152 @@
+using System.Linq.Dynamic.Core;
+using System.Reflection;
+using EFCore.BulkExtensions;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.ApiResponse;
+
+public class ApiResult
+{
+ ///
+ /// Private constructor called by the CreateAsync method.
+ ///
+ private ApiResult(
+ List data,
+ int count,
+ int pageIndex,
+ int pageSize,
+ string? filterQuery)
+ {
+ Data = data;
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ TotalCount = count;
+ TotalPages = (int)Math.Ceiling(count / (double)pageSize);
+ FilterQuery = filterQuery;
+ }
+
+ #region Methods
+
+ ///
+ /// Pages, sorts and/or filters a IQueryable source.
+ ///
+ /// An IQueryable source of generic
+ /// type
+ /// Zero-based current page index
+ /// (0 = first page)
+ /// The actual size of
+ /// each page
+ /// The filtering query (value to
+ /// lookup)
+ ///
+ /// A object containing the IQueryable paged/sorted/filtered
+ /// result
+ /// and all the relevant paging/sorting/filtering navigation
+ /// info.
+ ///
+ public static async Task> CreateAsync(
+ IQueryable source,
+ int pageIndex,
+ int pageSize,
+ string? filterQuery = null)
+ {
+ if (!string.IsNullOrEmpty(filterQuery))
+ {
+ source = source.Where(filterQuery);
+ }
+
+ var count = await source.CountAsync();
+
+ source = source
+ .Skip(pageIndex * pageSize)
+ .Take(pageSize);
+
+#if DEBUG
+ // retrieve the SQL query (for debug purposes)
+ var sql = source.ToParametrizedSql();
+#endif
+
+ var data = await source.ToListAsync();
+
+ return new ApiResult(
+ data,
+ count,
+ pageIndex,
+ pageSize,
+ filterQuery);
+ }
+
+ ///
+ /// Checks if the given property name exists
+ /// to protect against SQL injection attacks
+ ///
+ public static bool IsValidProperty(
+ string propertyName,
+ bool throwExceptionIfNotFound = true)
+ {
+ var prop = typeof(T).GetProperty(
+ propertyName,
+ BindingFlags.IgnoreCase |
+ BindingFlags.Public |
+ BindingFlags.Static |
+ BindingFlags.Instance);
+ if (prop == null && throwExceptionIfNotFound)
+ throw new NotSupportedException($"ERROR: Property '{propertyName}' does not exist.");
+ return prop != null;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// IQueryable data result to return.
+ ///
+ public List Data { get; private set; }
+
+ ///
+ /// Zero-based index of current page.
+ ///
+ public int PageIndex { get; private set; }
+
+ ///
+ /// Number of items contained in each page.
+ ///
+ public int PageSize { get; private set; }
+
+ ///
+ /// Total items count
+ ///
+ public int TotalCount { get; private set; }
+
+ ///
+ /// Total pages count
+ ///
+ public int TotalPages { get; private set; }
+
+ ///
+ /// TRUE if the current page has a previous page,
+ /// FALSE otherwise.
+ ///
+ public bool HasPreviousPage
+ {
+ get { return (PageIndex > 0); }
+ }
+
+ ///
+ /// TRUE if the current page has a next page, FALSE otherwise.
+ ///
+ public bool HasNextPage
+ {
+ get { return ((PageIndex + 1) < TotalPages); }
+ }
+
+
+ ///
+ /// Filter Query string
+ /// (to be used within the given FilterColumn)
+ ///
+ public string? FilterQuery { get; set; }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs
new file mode 100644
index 0000000..2253c59
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IAuthorRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs
new file mode 100644
index 0000000..e6bac7d
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IBookRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs
new file mode 100644
index 0000000..9575d32
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface ICategoryRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs
new file mode 100644
index 0000000..b7aa2f2
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IPublisherRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs
new file mode 100644
index 0000000..032d48e
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs
@@ -0,0 +1,15 @@
+using System.Linq.Expressions;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IRepositoryBase where T: class
+{
+ T FindById(Guid id);
+ IQueryable FindByCondition(Expression> expression, bool trackChanges);
+ IQueryable FindAll(bool trackChanges);
+ void Add(T entity);
+ void AddRange(IEnumerable entities);
+ void Update(T entity);
+ void Remove(T entity);
+ void RemoveRange(IEnumerable entities);
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs
new file mode 100644
index 0000000..49bc705
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs
@@ -0,0 +1,11 @@
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IUnitOfWork: IDisposable
+{
+ IAuthorRepository Authors { get; }
+ IBookRepository Books { get; }
+ IPublisherRepository Publishers { get; }
+ ICategoryRepository Categories { get; }
+
+ int Complete();
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/AuthorController.cs b/LibraryManagementApp/Controllers/AuthorController.cs
new file mode 100644
index 0000000..b39220c
--- /dev/null
+++ b/LibraryManagementApp/Controllers/AuthorController.cs
@@ -0,0 +1,122 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class AuthorController: ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public AuthorController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetAuthors(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var authors = await ApiResult.CreateAsync(
+ _unitOfWork.Authors.FindAll(trackChanges).Select(
+ a => new AuthorDto()
+ {
+ Id = a.Id,
+ FirstName = a.FirstName,
+ LastName = a.LastName,
+ PublisherName = a.Publisher.Name,
+ AvatarUrl = a.AvatarUrl
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return authors;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetAuthorById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Authors
+ .FindByCondition(a => a.Id.Equals(id), trackChanges)
+ .Select(a => new AuthorDto()
+ {
+ Id = a.Id,
+ FirstName = a.FirstName,
+ LastName = a.LastName,
+ PublisherName = a.Publisher.Name,
+ AvatarUrl = a.AvatarUrl
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreateAuthor(AuthorDto author)
+ {
+ var entity = new Author
+ {
+ FirstName = author.FirstName,
+ LastName = author.LastName,
+ AvatarUrl = author.AvatarUrl,
+ PublisherId = author.PublisherId
+ };
+
+ _unitOfWork.Authors.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdateAuthor(AuthorDto author, Guid id)
+ {
+ var entity = _unitOfWork.Authors.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.FirstName = author.FirstName;
+ entity.LastName = author.LastName;
+ entity.AvatarUrl = author.AvatarUrl;
+ entity.PublisherId = author.PublisherId;
+
+
+ _unitOfWork.Authors.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeleteAuthor(Guid id)
+ {
+ var entity = _unitOfWork.Authors.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Authors.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/BookController.cs b/LibraryManagementApp/Controllers/BookController.cs
new file mode 100644
index 0000000..fb3ba4b
--- /dev/null
+++ b/LibraryManagementApp/Controllers/BookController.cs
@@ -0,0 +1,134 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class BookController : ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public BookController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetBooks(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var books = await ApiResult.CreateAsync(
+ _unitOfWork.Books.FindAll(trackChanges).Select(
+ b => new BookDto()
+ {
+ Id = b.Id,
+ Title = b.Title,
+ CopyrightNotice = b.CopyrightNotice,
+ ISBN = b.ISBN,
+ AuthorName = b.Author.FirstName,
+ PageLength = b.PageLength,
+ Language = b.Language,
+ ReleaseYear = b.ReleaseYear
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return books;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetBookById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Books
+ .FindByCondition(a => a.Id.Equals(id), trackChanges)
+ .Select(b => new BookDto()
+ {
+ Id = b.Id,
+ Title = b.Title,
+ CopyrightNotice = b.CopyrightNotice,
+ ISBN = b.ISBN,
+ AuthorName = b.Author.FirstName,
+ PageLength = b.PageLength,
+ Language = b.Language,
+ ReleaseYear = b.ReleaseYear
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreateBook(BookDto book)
+ {
+ var author = _unitOfWork.Authors.FindById(book.AuthourId);
+ var entity = new Book
+ {
+ Title = book.Title,
+ CopyrightNotice = book.CopyrightNotice,
+ ISBN = book.ISBN,
+ AuthorId = author.Id,
+ PageLength = book.PageLength,
+ Language = book.Language,
+ ReleaseYear = book.ReleaseYear
+ };
+
+ _unitOfWork.Books.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdateBook(BookDto book, Guid id)
+ {
+ var entity = _unitOfWork.Books.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.Title = book.Title;
+ entity.CopyrightNotice = book.CopyrightNotice;
+ entity.ISBN = book.ISBN;
+ entity.PageLength = book.PageLength;
+ entity.Language = book.Language;
+ entity.ReleaseYear = book.ReleaseYear;
+
+
+ _unitOfWork.Books.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeleteBook(Guid id)
+ {
+ var entity = _unitOfWork.Books.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Books.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/CategoryController.cs b/LibraryManagementApp/Controllers/CategoryController.cs
new file mode 100644
index 0000000..0392adf
--- /dev/null
+++ b/LibraryManagementApp/Controllers/CategoryController.cs
@@ -0,0 +1,113 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class CategoryController: ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public CategoryController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetPublishers(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var categories = await ApiResult.CreateAsync(
+ _unitOfWork.Categories.FindAll(trackChanges).Select(
+ c => new CategoryDto()
+ {
+ Id = c.Id,
+ Name = c.Name,
+ Description = c.Description
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return categories;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetCategoryById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Categories
+ .FindByCondition(a => a.Id.Equals(id), trackChanges)
+ .Select(c => new CategoryDto()
+ {
+ Id = c.Id,
+ Name = c.Name,
+ Description = c.Description
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreateCategory(CategoryDto category)
+ {
+ var entity = new Category
+ {
+ Name = category.Name,
+ Description = category.Description,
+ };
+
+ _unitOfWork.Categories.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdateCategory(CategoryDto category, Guid id)
+ {
+ var entity = _unitOfWork.Categories.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.Name = category.Name;
+ entity.Description = category.Description;
+
+ _unitOfWork.Categories.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeleteCategory(Guid id)
+ {
+ var entity = _unitOfWork.Categories.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Categories.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/BaseEntity.cs b/LibraryManagementApp/Domain/BaseEntity.cs
new file mode 100644
index 0000000..5f3c4ea
--- /dev/null
+++ b/LibraryManagementApp/Domain/BaseEntity.cs
@@ -0,0 +1,23 @@
+namespace LibraryManagementApp.Domain;
+
+public class BaseEntity
+{
+ public BaseEntity()
+ {
+
+ }
+
+ public BaseEntity(Guid id, DateTime createdOn)
+ {
+ Id = new Guid();
+ CreatedOn = createdOn;
+ }
+
+ public Guid Id { get; init; }
+ public DateTime CreatedOn { get; init; }
+ public Guid CreatedBy { get; init; }
+ public DateTime ModifiedOn { get; set; }
+ public Guid ModifiedBy { get; set; }
+ public DateTime DeletedOn { get; init; }
+ public Guid DeletedBy { get; init; }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/AuthorDto.cs b/LibraryManagementApp/Dtos/AuthorDto.cs
new file mode 100644
index 0000000..981bbeb
--- /dev/null
+++ b/LibraryManagementApp/Dtos/AuthorDto.cs
@@ -0,0 +1,11 @@
+namespace LibraryManagementApp.Dtos;
+
+public record AuthorDto
+{
+ public Guid Id { get; init; }
+ public string FirstName{get; init;}
+ public string LastName{get; init;}
+ public string AvatarUrl{get; init;}
+ public string PublisherName{get; init;}
+ public Guid PublisherId {get; init;}
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/BookDto.cs b/LibraryManagementApp/Dtos/BookDto.cs
new file mode 100644
index 0000000..f4799a6
--- /dev/null
+++ b/LibraryManagementApp/Dtos/BookDto.cs
@@ -0,0 +1,16 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Dtos;
+
+public record BookDto
+{
+ public Guid Id { get; init; }
+ public string Title{get; init;}
+ public string CopyrightNotice{get; init;}
+ public int ISBN{get; init;}
+ public string AuthorName { get; init; }
+ public Guid AuthourId { get; init; }
+ public int PageLength{get; init;}
+ public Language Language{get; init;}
+ public DateOnly ReleaseYear{get; init;}
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/CategoryDto.cs b/LibraryManagementApp/Dtos/CategoryDto.cs
new file mode 100644
index 0000000..fb156db
--- /dev/null
+++ b/LibraryManagementApp/Dtos/CategoryDto.cs
@@ -0,0 +1,8 @@
+namespace LibraryManagementApp.Dtos;
+
+public record CategoryDto
+{
+ public Guid Id { get; init; }
+ public string Name{get; set;}
+ public string Description{get; set;}
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/PublisherDto.cs b/LibraryManagementApp/Dtos/PublisherDto.cs
new file mode 100644
index 0000000..e701323
--- /dev/null
+++ b/LibraryManagementApp/Dtos/PublisherDto.cs
@@ -0,0 +1,10 @@
+namespace LibraryManagementApp.Dtos;
+
+public record PublisherDto
+{
+ public Guid Id { get; init; }
+ public string Name{get; init;}
+ public string LogoUrl{get; init;}
+ public int? TotalAuthors { get; init; }
+ public int? TotalBooks { get; init; }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/ApplicationDbContext.cs b/LibraryManagementApp/Persistence/ApplicationDbContext.cs
new file mode 100644
index 0000000..365bfea
--- /dev/null
+++ b/LibraryManagementApp/Persistence/ApplicationDbContext.cs
@@ -0,0 +1,26 @@
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Persistence.Configurations;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Persistence;
+
+public class ApplicationDbContext: DbContext
+{
+ public ApplicationDbContext(DbContextOptions options) : base(options)
+ {
+
+ }
+
+ public DbSet Authors => Set();
+ public DbSet Books => Set();
+ public DbSet Categories => Set();
+ public DbSet Publishers => Set();
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.ApplyConfiguration(new AuthorConfiguration());
+ modelBuilder.ApplyConfiguration(new BookConfiguration());
+ modelBuilder.ApplyConfiguration(new CategoryConfiguration());
+ modelBuilder.ApplyConfiguration(new PublisherConfiguration());
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Configurations/AuthorConfiguration.cs b/LibraryManagementApp/Persistence/Configurations/AuthorConfiguration.cs
new file mode 100644
index 0000000..daa1236
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Configurations/AuthorConfiguration.cs
@@ -0,0 +1,15 @@
+using LibraryManagementApp.Domain;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace LibraryManagementApp.Persistence.Configurations;
+
+public class AuthorConfiguration: IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.Property(a => a.Id)
+ .IsRequired();
+ builder.HasMany(a => a.Books);
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Configurations/BookConfiguration.cs b/LibraryManagementApp/Persistence/Configurations/BookConfiguration.cs
new file mode 100644
index 0000000..64d2bd8
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Configurations/BookConfiguration.cs
@@ -0,0 +1,17 @@
+using LibraryManagementApp.Domain;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace LibraryManagementApp.Persistence.Configurations;
+
+public class BookConfiguration: IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ /*builder.Property(b => b.Id)
+ .IsRequired();
+ builder.HasOne(b => b.Author)
+ .WithMany(a => a.Books)
+ .HasForeignKey(b => b.AuthorId);*/
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Configurations/CategoryConfiguration.cs b/LibraryManagementApp/Persistence/Configurations/CategoryConfiguration.cs
new file mode 100644
index 0000000..30cd565
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Configurations/CategoryConfiguration.cs
@@ -0,0 +1,16 @@
+using LibraryManagementApp.Domain;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace LibraryManagementApp.Persistence.Configurations;
+
+public class CategoryConfiguration : IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.Property(b => b.Id)
+ .IsRequired();
+ builder.HasMany(b => b.Books)
+ .WithMany();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Configurations/PublisherConfiguration.cs b/LibraryManagementApp/Persistence/Configurations/PublisherConfiguration.cs
new file mode 100644
index 0000000..7a1223a
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Configurations/PublisherConfiguration.cs
@@ -0,0 +1,16 @@
+using LibraryManagementApp.Domain;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace LibraryManagementApp.Persistence.Configurations;
+
+public class PublisherConfiguration: IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.Property(p => p.Id)
+ .IsRequired();
+ builder.HasMany(p => p.Books)
+ .WithOne();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Repository/AuthorRepository.cs b/LibraryManagementApp/Persistence/Repository/AuthorRepository.cs
new file mode 100644
index 0000000..0884e18
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Repository/AuthorRepository.cs
@@ -0,0 +1,11 @@
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Persistence.Repository;
+
+public class AuthorRepository: RepositoryBase, IAuthorRepository
+{
+ public AuthorRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Repository/BookRepository.cs b/LibraryManagementApp/Persistence/Repository/BookRepository.cs
new file mode 100644
index 0000000..4e151c0
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Repository/BookRepository.cs
@@ -0,0 +1,11 @@
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Persistence.Repository;
+
+public class BookRepository: RepositoryBase, IBookRepository
+{
+ public BookRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Repository/CategoryRepository.cs b/LibraryManagementApp/Persistence/Repository/CategoryRepository.cs
new file mode 100644
index 0000000..7d5ed2b
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Repository/CategoryRepository.cs
@@ -0,0 +1,11 @@
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Persistence.Repository;
+
+public class CategoryRepository: RepositoryBase, ICategoryRepository
+{
+ public CategoryRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Repository/PublisherRepository.cs b/LibraryManagementApp/Persistence/Repository/PublisherRepository.cs
new file mode 100644
index 0000000..822a685
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Repository/PublisherRepository.cs
@@ -0,0 +1,11 @@
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Persistence.Repository;
+
+public class PublisherRepository: RepositoryBase, IPublisherRepository
+{
+ public PublisherRepository(ApplicationDbContext context) : base(context)
+ {
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Repository/RepositoryBase.cs b/LibraryManagementApp/Persistence/Repository/RepositoryBase.cs
new file mode 100644
index 0000000..706136e
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Repository/RepositoryBase.cs
@@ -0,0 +1,45 @@
+using System.Linq.Expressions;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Persistence.Repository;
+
+public class RepositoryBase: IRepositoryBase where T: class
+{
+ protected readonly ApplicationDbContext _context;
+
+ public RepositoryBase(ApplicationDbContext context) =>
+ _context = context;
+
+ public T FindById(Guid id) =>
+ _context.Set().Find(id);
+
+ public IQueryable FindByCondition(Expression> expression, bool trackChanges) =>
+ !trackChanges ?
+ _context.Set()
+ .Where(expression)
+ .AsNoTracking() :
+ _context.Set()
+ .Where(expression);
+
+ public IQueryable FindAll(bool trackChanges) =>
+ !trackChanges ?
+ _context.Set()
+ .AsNoTracking() :
+ _context.Set();
+
+ public void Add(T entity) =>
+ _context.Set().Add(entity);
+
+ public void AddRange(IEnumerable entities) =>
+ _context.Set().AddRange(entities);
+
+ public void Update(T entity) =>
+ _context.Set().Update(entity);
+
+ public void Remove(T entity) =>
+ _context.Set().Remove(entity);
+
+ public void RemoveRange(IEnumerable entities) =>
+ _context.Set().RemoveRange(entities);
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Persistence/Repository/UnitOfWork.cs b/LibraryManagementApp/Persistence/Repository/UnitOfWork.cs
new file mode 100644
index 0000000..8b64d33
--- /dev/null
+++ b/LibraryManagementApp/Persistence/Repository/UnitOfWork.cs
@@ -0,0 +1,28 @@
+using LibraryManagementApp.Contracts.RepositoryContracts;
+
+namespace LibraryManagementApp.Persistence.Repository;
+
+public class UnitOfWork: IUnitOfWork
+{
+ private readonly ApplicationDbContext _context;
+
+ public UnitOfWork(ApplicationDbContext context)
+ {
+ _context = context;
+ Authors = new AuthorRepository(_context);
+ Books = new BookRepository(_context);
+ Publishers = new PublisherRepository(_context);
+ Categories = new CategoryRepository(_context);
+ }
+
+ public IAuthorRepository Authors { get; private set; }
+ public IBookRepository Books { get; private set; }
+ public IPublisherRepository Publishers { get; private set; }
+ public ICategoryRepository Categories { get; private set; }
+
+ public int Complete() =>
+ _context.SaveChanges();
+
+ public void Dispose() =>
+ _context.Dispose();
+}
\ No newline at end of file
From cd94afc87195357f38b616348874b6f271183ce4 Mon Sep 17 00:00:00 2001
From: sunkanmi
Date: Sat, 11 Mar 2023 10:07:35 -0500
Subject: [PATCH 5/5] libraryManagementAdded
---
.../086591F1B63CEC976440DC2952AC4138.txt | 5 +
.../0E84027714179DA860EC36BE3ABC2CCE.txt | 5 +
.../1BBCFB82D95A66785DABF16FE16DD079.txt | 5 +
.../7445BDA0F89FE36B4BC831F76CB0533A.txt | 5 +
.../A91CCAE139380AA1368393C8FC2953C1.txt | 5 +
.../B56FD7BF4AB39D813239C006C4FF5813.txt | 5 +
.../6A3B12DA60987AF16E55F3FCEC2A6EED.txt | 8 +
.../7A362B30780DD15E6D710EC44AA0E023.txt | 8 +
.../C19291F87C625505E0CB012E128C3E33.txt | 8 +
.../FA2111BDFC79125C0CF1D96B53B88FEB.txt | 8 +
.../FE6FC17D485932CC797BB376BB501D44.txt | 8 +
LibraryManagementApp/ApiResponse/ApiResult.cs | 152 ++++++++++
.../RepositoryContracts/IAuthorRepository.cs | 8 +
.../RepositoryContracts/IBookRepository.cs | 8 +
.../ICategoryRepository.cs | 8 +
.../IPublisherRepository.cs | 8 +
.../RepositoryContracts/IRepositoryBase.cs | 15 +
.../RepositoryContracts/IUnitOfWork.cs | 11 +
.../Controllers/AuthorController.cs | 122 ++++++++
.../Controllers/BookController.cs | 134 +++++++++
.../Controllers/CategoryController.cs | 113 ++++++++
.../Controllers/PublisherController.cs | 114 ++++++++
LibraryManagementApp/Domain/Author.cs | 40 +++
LibraryManagementApp/Domain/BaseEntity.cs | 23 ++
LibraryManagementApp/Domain/Book.cs | 26 ++
LibraryManagementApp/Domain/Category.cs | 24 ++
LibraryManagementApp/Domain/Language.cs | 11 +
LibraryManagementApp/Domain/Publisher.cs | 52 ++++
LibraryManagementApp/Dtos/AuthorDto.cs | 11 +
LibraryManagementApp/Dtos/BookDto.cs | 16 ++
LibraryManagementApp/Dtos/CategoryDto.cs | 8 +
LibraryManagementApp/Dtos/PublisherDto.cs | 10 +
.../Exceptions/NotFoundException.cs | 24 ++
.../LibraryManagementApp.csproj | 23 ++
.../20230309042120_Initial.Designer.cs | 262 ++++++++++++++++++
.../Migrations/20230309042120_Initial.cs | 168 +++++++++++
.../ApplicationDbContextModelSnapshot.cs | 259 +++++++++++++++++
.../Persistence/ApplicationDbContext.cs | 26 ++
.../Configurations/AuthorConfiguration.cs | 15 +
.../Configurations/BookConfiguration.cs | 17 ++
.../Configurations/CategoryConfiguration.cs | 16 ++
.../Configurations/PublisherConfiguration.cs | 16 ++
.../Repository/AuthorRepository.cs | 11 +
.../Persistence/Repository/BookRepository.cs | 11 +
.../Repository/CategoryRepository.cs | 11 +
.../Repository/PublisherRepository.cs | 11 +
.../Persistence/Repository/RepositoryBase.cs | 45 +++
.../Persistence/Repository/UnitOfWork.cs | 28 ++
LibraryManagementApp/Program.cs | 41 +++
.../Properties/launchSettings.json | 41 +++
.../appsettings.Development.json | 8 +
LibraryManagementApp/appsettings.json | 12 +
52 files changed, 2029 insertions(+)
create mode 100644 BankingSoftware/Storage/Accounts/086591F1B63CEC976440DC2952AC4138.txt
create mode 100644 BankingSoftware/Storage/Accounts/0E84027714179DA860EC36BE3ABC2CCE.txt
create mode 100644 BankingSoftware/Storage/Accounts/1BBCFB82D95A66785DABF16FE16DD079.txt
create mode 100644 BankingSoftware/Storage/Accounts/7445BDA0F89FE36B4BC831F76CB0533A.txt
create mode 100644 BankingSoftware/Storage/Accounts/A91CCAE139380AA1368393C8FC2953C1.txt
create mode 100644 BankingSoftware/Storage/Accounts/B56FD7BF4AB39D813239C006C4FF5813.txt
create mode 100644 BankingSoftware/Storage/Users/6A3B12DA60987AF16E55F3FCEC2A6EED.txt
create mode 100644 BankingSoftware/Storage/Users/7A362B30780DD15E6D710EC44AA0E023.txt
create mode 100644 BankingSoftware/Storage/Users/C19291F87C625505E0CB012E128C3E33.txt
create mode 100644 BankingSoftware/Storage/Users/FA2111BDFC79125C0CF1D96B53B88FEB.txt
create mode 100644 BankingSoftware/Storage/Users/FE6FC17D485932CC797BB376BB501D44.txt
create mode 100644 LibraryManagementApp/ApiResponse/ApiResult.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs
create mode 100644 LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs
create mode 100644 LibraryManagementApp/Controllers/AuthorController.cs
create mode 100644 LibraryManagementApp/Controllers/BookController.cs
create mode 100644 LibraryManagementApp/Controllers/CategoryController.cs
create mode 100644 LibraryManagementApp/Controllers/PublisherController.cs
create mode 100644 LibraryManagementApp/Domain/Author.cs
create mode 100644 LibraryManagementApp/Domain/BaseEntity.cs
create mode 100644 LibraryManagementApp/Domain/Book.cs
create mode 100644 LibraryManagementApp/Domain/Category.cs
create mode 100644 LibraryManagementApp/Domain/Language.cs
create mode 100644 LibraryManagementApp/Domain/Publisher.cs
create mode 100644 LibraryManagementApp/Dtos/AuthorDto.cs
create mode 100644 LibraryManagementApp/Dtos/BookDto.cs
create mode 100644 LibraryManagementApp/Dtos/CategoryDto.cs
create mode 100644 LibraryManagementApp/Dtos/PublisherDto.cs
create mode 100644 LibraryManagementApp/Exceptions/NotFoundException.cs
create mode 100644 LibraryManagementApp/LibraryManagementApp.csproj
create mode 100644 LibraryManagementApp/Migrations/20230309042120_Initial.Designer.cs
create mode 100644 LibraryManagementApp/Migrations/20230309042120_Initial.cs
create mode 100644 LibraryManagementApp/Migrations/ApplicationDbContextModelSnapshot.cs
create mode 100644 LibraryManagementApp/Persistence/ApplicationDbContext.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/AuthorConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/BookConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/CategoryConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Configurations/PublisherConfiguration.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/AuthorRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/BookRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/CategoryRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/PublisherRepository.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/RepositoryBase.cs
create mode 100644 LibraryManagementApp/Persistence/Repository/UnitOfWork.cs
create mode 100644 LibraryManagementApp/Program.cs
create mode 100644 LibraryManagementApp/Properties/launchSettings.json
create mode 100644 LibraryManagementApp/appsettings.Development.json
create mode 100644 LibraryManagementApp/appsettings.json
diff --git a/BankingSoftware/Storage/Accounts/086591F1B63CEC976440DC2952AC4138.txt b/BankingSoftware/Storage/Accounts/086591F1B63CEC976440DC2952AC4138.txt
new file mode 100644
index 0000000..2f3dfb6
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/086591F1B63CEC976440DC2952AC4138.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: $0
+Last withdrawal time:
+Last deposit amount: $0
+Last deposit time:
+Total: $0
diff --git a/BankingSoftware/Storage/Accounts/0E84027714179DA860EC36BE3ABC2CCE.txt b/BankingSoftware/Storage/Accounts/0E84027714179DA860EC36BE3ABC2CCE.txt
new file mode 100644
index 0000000..3df7b09
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/0E84027714179DA860EC36BE3ABC2CCE.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: 20000
+Last withdrawal time: 3/3/2023 9:01:46 AM
+Last deposit amount: 60000
+Last deposit time: 3/3/2023 9:01:34 AM
+Total: $40000
diff --git a/BankingSoftware/Storage/Accounts/1BBCFB82D95A66785DABF16FE16DD079.txt b/BankingSoftware/Storage/Accounts/1BBCFB82D95A66785DABF16FE16DD079.txt
new file mode 100644
index 0000000..f7a2f63
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/1BBCFB82D95A66785DABF16FE16DD079.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: 50000
+Last withdrawal time: 3/3/2023 8:55:01 AM
+Last deposit amount: 80000
+Last deposit time: 3/3/2023 8:54:50 AM
+Total: $30000
diff --git a/BankingSoftware/Storage/Accounts/7445BDA0F89FE36B4BC831F76CB0533A.txt b/BankingSoftware/Storage/Accounts/7445BDA0F89FE36B4BC831F76CB0533A.txt
new file mode 100644
index 0000000..2f3dfb6
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/7445BDA0F89FE36B4BC831F76CB0533A.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: $0
+Last withdrawal time:
+Last deposit amount: $0
+Last deposit time:
+Total: $0
diff --git a/BankingSoftware/Storage/Accounts/A91CCAE139380AA1368393C8FC2953C1.txt b/BankingSoftware/Storage/Accounts/A91CCAE139380AA1368393C8FC2953C1.txt
new file mode 100644
index 0000000..15c2903
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/A91CCAE139380AA1368393C8FC2953C1.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: 20000
+Last withdrawal time: 3/3/2023 8:47:41 AM
+Last deposit amount: 80000
+Last deposit time: 3/3/2023 8:47:30 AM
+Total: $60000
diff --git a/BankingSoftware/Storage/Accounts/B56FD7BF4AB39D813239C006C4FF5813.txt b/BankingSoftware/Storage/Accounts/B56FD7BF4AB39D813239C006C4FF5813.txt
new file mode 100644
index 0000000..4c63b6b
--- /dev/null
+++ b/BankingSoftware/Storage/Accounts/B56FD7BF4AB39D813239C006C4FF5813.txt
@@ -0,0 +1,5 @@
+Last withdrawal amount: 30000
+Last withdrawal time: 3/3/2023 9:09:01 AM
+Last deposit amount: $60000
+Last deposit time: 3/3/2023 9:08:49 AM
+Total: $30000
diff --git a/BankingSoftware/Storage/Users/6A3B12DA60987AF16E55F3FCEC2A6EED.txt b/BankingSoftware/Storage/Users/6A3B12DA60987AF16E55F3FCEC2A6EED.txt
new file mode 100644
index 0000000..a8c4c60
--- /dev/null
+++ b/BankingSoftware/Storage/Users/6A3B12DA60987AF16E55F3FCEC2A6EED.txt
@@ -0,0 +1,8 @@
+First Name: Kunle
+Last Name: Afod
+Email: kunle@afod.com
+Username: kunle
+Age: 67
+Phone Number: 8734652345
+HashedPassword: F1A3AB9E8E8AB970167FEEE7A731F3E9
+
diff --git a/BankingSoftware/Storage/Users/7A362B30780DD15E6D710EC44AA0E023.txt b/BankingSoftware/Storage/Users/7A362B30780DD15E6D710EC44AA0E023.txt
new file mode 100644
index 0000000..bc3adbb
--- /dev/null
+++ b/BankingSoftware/Storage/Users/7A362B30780DD15E6D710EC44AA0E023.txt
@@ -0,0 +1,8 @@
+First Name: Usher
+Last Name: Ray
+Email: usher@ray.com
+Username: usher
+Age: 87
+Phone Number: 8975346523
+HashedPassword: BA4AFECD23BE0B3121EA708831022CEF
+
diff --git a/BankingSoftware/Storage/Users/C19291F87C625505E0CB012E128C3E33.txt b/BankingSoftware/Storage/Users/C19291F87C625505E0CB012E128C3E33.txt
new file mode 100644
index 0000000..738de81
--- /dev/null
+++ b/BankingSoftware/Storage/Users/C19291F87C625505E0CB012E128C3E33.txt
@@ -0,0 +1,8 @@
+First Name: Hal
+Last Name: Finley
+Email: hal@finley.com
+Username: hal
+Age: 87
+Phone Number: 9874523876
+HashedPassword: 8E3F0695D2604D26F5B64C23C485E3BF
+
diff --git a/BankingSoftware/Storage/Users/FA2111BDFC79125C0CF1D96B53B88FEB.txt b/BankingSoftware/Storage/Users/FA2111BDFC79125C0CF1D96B53B88FEB.txt
new file mode 100644
index 0000000..7ebdd13
--- /dev/null
+++ b/BankingSoftware/Storage/Users/FA2111BDFC79125C0CF1D96B53B88FEB.txt
@@ -0,0 +1,8 @@
+First Name: John
+Last Name: Camark
+Email: john@camark.com
+Username: john
+Age: 67
+Phone Number: 9834562346
+HashedPassword: E813ECD4F0196D88949044C1FA1B568D
+
diff --git a/BankingSoftware/Storage/Users/FE6FC17D485932CC797BB376BB501D44.txt b/BankingSoftware/Storage/Users/FE6FC17D485932CC797BB376BB501D44.txt
new file mode 100644
index 0000000..d548215
--- /dev/null
+++ b/BankingSoftware/Storage/Users/FE6FC17D485932CC797BB376BB501D44.txt
@@ -0,0 +1,8 @@
+First Name: Hailey
+Last Name: Bieber
+Email: hailey@bieber.com
+Username: hailey
+Age: 78
+Phone Number: 8777345623
+HashedPassword: 588BE3DDB98C4DB0FB1E484105399596
+
diff --git a/LibraryManagementApp/ApiResponse/ApiResult.cs b/LibraryManagementApp/ApiResponse/ApiResult.cs
new file mode 100644
index 0000000..e91825b
--- /dev/null
+++ b/LibraryManagementApp/ApiResponse/ApiResult.cs
@@ -0,0 +1,152 @@
+using System.Linq.Dynamic.Core;
+using System.Reflection;
+using EFCore.BulkExtensions;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.ApiResponse;
+
+public class ApiResult
+{
+ ///
+ /// Private constructor called by the CreateAsync method.
+ ///
+ private ApiResult(
+ List data,
+ int count,
+ int pageIndex,
+ int pageSize,
+ string? filterQuery)
+ {
+ Data = data;
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ TotalCount = count;
+ TotalPages = (int)Math.Ceiling(count / (double)pageSize);
+ FilterQuery = filterQuery;
+ }
+
+ #region Methods
+
+ ///
+ /// Pages, sorts and/or filters a IQueryable source.
+ ///
+ /// An IQueryable source of generic
+ /// type
+ /// Zero-based current page index
+ /// (0 = first page)
+ /// The actual size of
+ /// each page
+ /// The filtering query (value to
+ /// lookup)
+ ///
+ /// A object containing the IQueryable paged/sorted/filtered
+ /// result
+ /// and all the relevant paging/sorting/filtering navigation
+ /// info.
+ ///
+ public static async Task> CreateAsync(
+ IQueryable source,
+ int pageIndex,
+ int pageSize,
+ string? filterQuery = null)
+ {
+ if (!string.IsNullOrEmpty(filterQuery))
+ {
+ source = source.Where(filterQuery);
+ }
+
+ var count = await source.CountAsync();
+
+ source = source
+ .Skip(pageIndex * pageSize)
+ .Take(pageSize);
+
+#if DEBUG
+ // retrieve the SQL query (for debug purposes)
+ var sql = source.ToParametrizedSql();
+#endif
+
+ var data = await source.ToListAsync();
+
+ return new ApiResult(
+ data,
+ count,
+ pageIndex,
+ pageSize,
+ filterQuery);
+ }
+
+ ///
+ /// Checks if the given property name exists
+ /// to protect against SQL injection attacks
+ ///
+ public static bool IsValidProperty(
+ string propertyName,
+ bool throwExceptionIfNotFound = true)
+ {
+ var prop = typeof(T).GetProperty(
+ propertyName,
+ BindingFlags.IgnoreCase |
+ BindingFlags.Public |
+ BindingFlags.Static |
+ BindingFlags.Instance);
+ if (prop == null && throwExceptionIfNotFound)
+ throw new NotSupportedException($"ERROR: Property '{propertyName}' does not exist.");
+ return prop != null;
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// IQueryable data result to return.
+ ///
+ public List Data { get; private set; }
+
+ ///
+ /// Zero-based index of current page.
+ ///
+ public int PageIndex { get; private set; }
+
+ ///
+ /// Number of items contained in each page.
+ ///
+ public int PageSize { get; private set; }
+
+ ///
+ /// Total items count
+ ///
+ public int TotalCount { get; private set; }
+
+ ///
+ /// Total pages count
+ ///
+ public int TotalPages { get; private set; }
+
+ ///
+ /// TRUE if the current page has a previous page,
+ /// FALSE otherwise.
+ ///
+ public bool HasPreviousPage
+ {
+ get { return (PageIndex > 0); }
+ }
+
+ ///
+ /// TRUE if the current page has a next page, FALSE otherwise.
+ ///
+ public bool HasNextPage
+ {
+ get { return ((PageIndex + 1) < TotalPages); }
+ }
+
+
+ ///
+ /// Filter Query string
+ /// (to be used within the given FilterColumn)
+ ///
+ public string? FilterQuery { get; set; }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs
new file mode 100644
index 0000000..2253c59
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IAuthorRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IAuthorRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs
new file mode 100644
index 0000000..e6bac7d
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IBookRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IBookRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs
new file mode 100644
index 0000000..9575d32
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/ICategoryRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface ICategoryRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs
new file mode 100644
index 0000000..b7aa2f2
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IPublisherRepository.cs
@@ -0,0 +1,8 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IPublisherRepository: IRepositoryBase
+{
+
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs
new file mode 100644
index 0000000..032d48e
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IRepositoryBase.cs
@@ -0,0 +1,15 @@
+using System.Linq.Expressions;
+
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IRepositoryBase where T: class
+{
+ T FindById(Guid id);
+ IQueryable FindByCondition(Expression> expression, bool trackChanges);
+ IQueryable FindAll(bool trackChanges);
+ void Add(T entity);
+ void AddRange(IEnumerable entities);
+ void Update(T entity);
+ void Remove(T entity);
+ void RemoveRange(IEnumerable entities);
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs b/LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs
new file mode 100644
index 0000000..49bc705
--- /dev/null
+++ b/LibraryManagementApp/Contracts/RepositoryContracts/IUnitOfWork.cs
@@ -0,0 +1,11 @@
+namespace LibraryManagementApp.Contracts.RepositoryContracts;
+
+public interface IUnitOfWork: IDisposable
+{
+ IAuthorRepository Authors { get; }
+ IBookRepository Books { get; }
+ IPublisherRepository Publishers { get; }
+ ICategoryRepository Categories { get; }
+
+ int Complete();
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/AuthorController.cs b/LibraryManagementApp/Controllers/AuthorController.cs
new file mode 100644
index 0000000..b39220c
--- /dev/null
+++ b/LibraryManagementApp/Controllers/AuthorController.cs
@@ -0,0 +1,122 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class AuthorController: ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public AuthorController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetAuthors(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var authors = await ApiResult.CreateAsync(
+ _unitOfWork.Authors.FindAll(trackChanges).Select(
+ a => new AuthorDto()
+ {
+ Id = a.Id,
+ FirstName = a.FirstName,
+ LastName = a.LastName,
+ PublisherName = a.Publisher.Name,
+ AvatarUrl = a.AvatarUrl
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return authors;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetAuthorById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Authors
+ .FindByCondition(a => a.Id.Equals(id), trackChanges)
+ .Select(a => new AuthorDto()
+ {
+ Id = a.Id,
+ FirstName = a.FirstName,
+ LastName = a.LastName,
+ PublisherName = a.Publisher.Name,
+ AvatarUrl = a.AvatarUrl
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreateAuthor(AuthorDto author)
+ {
+ var entity = new Author
+ {
+ FirstName = author.FirstName,
+ LastName = author.LastName,
+ AvatarUrl = author.AvatarUrl,
+ PublisherId = author.PublisherId
+ };
+
+ _unitOfWork.Authors.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdateAuthor(AuthorDto author, Guid id)
+ {
+ var entity = _unitOfWork.Authors.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.FirstName = author.FirstName;
+ entity.LastName = author.LastName;
+ entity.AvatarUrl = author.AvatarUrl;
+ entity.PublisherId = author.PublisherId;
+
+
+ _unitOfWork.Authors.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeleteAuthor(Guid id)
+ {
+ var entity = _unitOfWork.Authors.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Authors.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/BookController.cs b/LibraryManagementApp/Controllers/BookController.cs
new file mode 100644
index 0000000..fb3ba4b
--- /dev/null
+++ b/LibraryManagementApp/Controllers/BookController.cs
@@ -0,0 +1,134 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class BookController : ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public BookController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetBooks(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var books = await ApiResult.CreateAsync(
+ _unitOfWork.Books.FindAll(trackChanges).Select(
+ b => new BookDto()
+ {
+ Id = b.Id,
+ Title = b.Title,
+ CopyrightNotice = b.CopyrightNotice,
+ ISBN = b.ISBN,
+ AuthorName = b.Author.FirstName,
+ PageLength = b.PageLength,
+ Language = b.Language,
+ ReleaseYear = b.ReleaseYear
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return books;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetBookById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Books
+ .FindByCondition(a => a.Id.Equals(id), trackChanges)
+ .Select(b => new BookDto()
+ {
+ Id = b.Id,
+ Title = b.Title,
+ CopyrightNotice = b.CopyrightNotice,
+ ISBN = b.ISBN,
+ AuthorName = b.Author.FirstName,
+ PageLength = b.PageLength,
+ Language = b.Language,
+ ReleaseYear = b.ReleaseYear
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreateBook(BookDto book)
+ {
+ var author = _unitOfWork.Authors.FindById(book.AuthourId);
+ var entity = new Book
+ {
+ Title = book.Title,
+ CopyrightNotice = book.CopyrightNotice,
+ ISBN = book.ISBN,
+ AuthorId = author.Id,
+ PageLength = book.PageLength,
+ Language = book.Language,
+ ReleaseYear = book.ReleaseYear
+ };
+
+ _unitOfWork.Books.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdateBook(BookDto book, Guid id)
+ {
+ var entity = _unitOfWork.Books.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.Title = book.Title;
+ entity.CopyrightNotice = book.CopyrightNotice;
+ entity.ISBN = book.ISBN;
+ entity.PageLength = book.PageLength;
+ entity.Language = book.Language;
+ entity.ReleaseYear = book.ReleaseYear;
+
+
+ _unitOfWork.Books.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeleteBook(Guid id)
+ {
+ var entity = _unitOfWork.Books.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Books.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/CategoryController.cs b/LibraryManagementApp/Controllers/CategoryController.cs
new file mode 100644
index 0000000..0392adf
--- /dev/null
+++ b/LibraryManagementApp/Controllers/CategoryController.cs
@@ -0,0 +1,113 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class CategoryController: ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public CategoryController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetPublishers(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var categories = await ApiResult.CreateAsync(
+ _unitOfWork.Categories.FindAll(trackChanges).Select(
+ c => new CategoryDto()
+ {
+ Id = c.Id,
+ Name = c.Name,
+ Description = c.Description
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return categories;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetCategoryById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Categories
+ .FindByCondition(a => a.Id.Equals(id), trackChanges)
+ .Select(c => new CategoryDto()
+ {
+ Id = c.Id,
+ Name = c.Name,
+ Description = c.Description
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreateCategory(CategoryDto category)
+ {
+ var entity = new Category
+ {
+ Name = category.Name,
+ Description = category.Description,
+ };
+
+ _unitOfWork.Categories.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdateCategory(CategoryDto category, Guid id)
+ {
+ var entity = _unitOfWork.Categories.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.Name = category.Name;
+ entity.Description = category.Description;
+
+ _unitOfWork.Categories.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeleteCategory(Guid id)
+ {
+ var entity = _unitOfWork.Categories.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Categories.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Controllers/PublisherController.cs b/LibraryManagementApp/Controllers/PublisherController.cs
new file mode 100644
index 0000000..16c6f78
--- /dev/null
+++ b/LibraryManagementApp/Controllers/PublisherController.cs
@@ -0,0 +1,114 @@
+using LibraryManagementApp.ApiResponse;
+using LibraryManagementApp.Contracts.RepositoryContracts;
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Dtos;
+using LibraryManagementApp.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class PublisherController : ControllerBase
+{
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly ILogger _logger;
+
+ public PublisherController(ILogger logger, IUnitOfWork unitOfWork)
+ {
+ _logger = logger;
+ _unitOfWork = unitOfWork;
+ }
+
+ [HttpGet]
+ public async Task>> GetPublishers(
+ bool trackChanges,
+ int pageIndex = 0,
+ int pageSize = 10,
+ string? filterQuery = null)
+ {
+ var publishers = await ApiResult.CreateAsync(
+ _unitOfWork.Publishers.FindAll(trackChanges).Select(
+ p => new PublisherDto()
+ {
+ Id = p.Id,
+ Name = p.Name,
+ LogoUrl = p.LogoUrl,
+ }),
+ pageIndex,
+ pageSize,
+ filterQuery);
+
+ return publishers;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetPublisherById(Guid id, bool trackChanges)
+ {
+ var entity = await _unitOfWork.Publishers
+ .FindByCondition(p => p.Id.Equals(id), trackChanges)
+ .Select(p => new PublisherDto
+ {
+ Name = p.Name,
+ LogoUrl = p.LogoUrl,
+ TotalBooks = p.TotBooks,
+ TotalAuthors = p.TotAuthors
+ })
+ .FirstOrDefaultAsync();
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ return entity;
+ }
+
+ [HttpPost]
+ public ActionResult CreatePublisher(PublisherDto publisher)
+ {
+ var entity = new Publisher
+ {
+ Name = publisher.Name,
+ LogoUrl = publisher.LogoUrl,
+ };
+
+ _unitOfWork.Publishers.Add(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpPut("{id:guid}")]
+ public ActionResult UpdatePublisher(PublisherDto publisher, Guid id)
+ {
+ var entity = _unitOfWork.Publishers.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ entity.Name = publisher.Name;
+ entity.LogoUrl = publisher.LogoUrl;
+
+ _unitOfWork.Publishers.Update(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+
+ [HttpDelete("{id:guid}")]
+ public ActionResult DeletePublisher(Guid id)
+ {
+ var entity = _unitOfWork.Publishers.FindById(id);
+
+ if (entity == null)
+ throw new NotFoundException();
+
+ _unitOfWork.Publishers.Remove(entity);
+ _unitOfWork.Complete();
+ _unitOfWork.Dispose();
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/Author.cs b/LibraryManagementApp/Domain/Author.cs
new file mode 100644
index 0000000..39a2f54
--- /dev/null
+++ b/LibraryManagementApp/Domain/Author.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace LibraryManagementApp.Domain
+{
+ public class Author: BaseEntity
+ {
+ public Author()
+ {
+
+ }
+
+ public Author(string firstName, string lastName, string avatarUrl, Guid publisherId)
+ {
+ FirstName = firstName;
+ LastName = lastName;
+ AvatarUrl = avatarUrl;
+ PublisherId = publisherId;
+ }
+
+ public string FirstName{get; set;}
+ public string LastName{get; set;}
+ public string AvatarUrl{get; set;}
+ public Guid PublisherId{get; set;}
+ public Publisher Publisher { get; set; }
+ public ICollection Books{get; set;}
+
+ [NotMapped]
+ public int TotBooks
+ {
+ get
+ {
+ return (Books != null)
+ ? Books.Count
+ : _TotBooks;
+ }
+ set => _TotBooks = value;
+ }
+ private int _TotBooks;
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/BaseEntity.cs b/LibraryManagementApp/Domain/BaseEntity.cs
new file mode 100644
index 0000000..5f3c4ea
--- /dev/null
+++ b/LibraryManagementApp/Domain/BaseEntity.cs
@@ -0,0 +1,23 @@
+namespace LibraryManagementApp.Domain;
+
+public class BaseEntity
+{
+ public BaseEntity()
+ {
+
+ }
+
+ public BaseEntity(Guid id, DateTime createdOn)
+ {
+ Id = new Guid();
+ CreatedOn = createdOn;
+ }
+
+ public Guid Id { get; init; }
+ public DateTime CreatedOn { get; init; }
+ public Guid CreatedBy { get; init; }
+ public DateTime ModifiedOn { get; set; }
+ public Guid ModifiedBy { get; set; }
+ public DateTime DeletedOn { get; init; }
+ public Guid DeletedBy { get; init; }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/Book.cs b/LibraryManagementApp/Domain/Book.cs
new file mode 100644
index 0000000..a480777
--- /dev/null
+++ b/LibraryManagementApp/Domain/Book.cs
@@ -0,0 +1,26 @@
+namespace LibraryManagementApp.Domain
+{
+ public class Book: BaseEntity
+ {
+ public Book()
+ {
+
+ }
+
+ public Book(string title, string copyrightNotice, Guid authorId)
+ {
+ Title = title;
+ CopyrightNotice = copyrightNotice;
+ AuthorId = authorId;
+ }
+
+ public string Title{get; set;}
+ public string CopyrightNotice{get; set;}
+ public int ISBN{get; set;}
+ public Guid AuthorId{get; set;}
+ public Author Author { get; set; }
+ public int PageLength{get; set;}
+ public Language Language{get; set;}
+ public DateOnly ReleaseYear{get; set;}
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/Category.cs b/LibraryManagementApp/Domain/Category.cs
new file mode 100644
index 0000000..74672ae
--- /dev/null
+++ b/LibraryManagementApp/Domain/Category.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace LibraryManagementApp.Domain
+{
+ public class Category: BaseEntity
+ {
+ public Category()
+ {
+
+ }
+ public Category(string name, string description)
+ {
+ Name = name;
+ Description = description;
+ }
+
+ public string Name{get; set;}
+ public string Description{get; set;}
+ public ICollection Books{get; set;}
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/Language.cs b/LibraryManagementApp/Domain/Language.cs
new file mode 100644
index 0000000..8ad94e9
--- /dev/null
+++ b/LibraryManagementApp/Domain/Language.cs
@@ -0,0 +1,11 @@
+namespace LibraryManagementApp.Domain
+{
+ public enum Language
+ {
+ English = 10,
+ Yoruba = 20,
+ Igbo = 30,
+ Hausa = 40,
+ French = 50,
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Domain/Publisher.cs b/LibraryManagementApp/Domain/Publisher.cs
new file mode 100644
index 0000000..48105de
--- /dev/null
+++ b/LibraryManagementApp/Domain/Publisher.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace LibraryManagementApp.Domain
+{
+ public class Publisher: BaseEntity
+ {
+ public Publisher()
+ {
+
+ }
+ public Publisher(string name, string logoUrl)
+ {
+ Name = name;
+ LogoUrl = logoUrl;
+ }
+
+ public string Name{get; set;}
+ public string LogoUrl{get; set;}
+ public ICollection Books { get; set; }
+ public ICollection Authors { get; set; }
+
+ [NotMapped]
+ public int TotBooks
+ {
+ get
+ {
+ return (Books != null)
+ ? Books.Count
+ : _TotBooks;
+ }
+ set => _TotBooks = value;
+ }
+ private int _TotBooks;
+
+ [NotMapped]
+ public int TotAuthors
+ {
+ get
+ {
+ return (Books != null)
+ ? Books.Count
+ : _TotBooks;
+ }
+ set => _TotBooks = value;
+ }
+ private int _TotAuthors;
+ }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/AuthorDto.cs b/LibraryManagementApp/Dtos/AuthorDto.cs
new file mode 100644
index 0000000..981bbeb
--- /dev/null
+++ b/LibraryManagementApp/Dtos/AuthorDto.cs
@@ -0,0 +1,11 @@
+namespace LibraryManagementApp.Dtos;
+
+public record AuthorDto
+{
+ public Guid Id { get; init; }
+ public string FirstName{get; init;}
+ public string LastName{get; init;}
+ public string AvatarUrl{get; init;}
+ public string PublisherName{get; init;}
+ public Guid PublisherId {get; init;}
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/BookDto.cs b/LibraryManagementApp/Dtos/BookDto.cs
new file mode 100644
index 0000000..f4799a6
--- /dev/null
+++ b/LibraryManagementApp/Dtos/BookDto.cs
@@ -0,0 +1,16 @@
+using LibraryManagementApp.Domain;
+
+namespace LibraryManagementApp.Dtos;
+
+public record BookDto
+{
+ public Guid Id { get; init; }
+ public string Title{get; init;}
+ public string CopyrightNotice{get; init;}
+ public int ISBN{get; init;}
+ public string AuthorName { get; init; }
+ public Guid AuthourId { get; init; }
+ public int PageLength{get; init;}
+ public Language Language{get; init;}
+ public DateOnly ReleaseYear{get; init;}
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/CategoryDto.cs b/LibraryManagementApp/Dtos/CategoryDto.cs
new file mode 100644
index 0000000..fb156db
--- /dev/null
+++ b/LibraryManagementApp/Dtos/CategoryDto.cs
@@ -0,0 +1,8 @@
+namespace LibraryManagementApp.Dtos;
+
+public record CategoryDto
+{
+ public Guid Id { get; init; }
+ public string Name{get; set;}
+ public string Description{get; set;}
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Dtos/PublisherDto.cs b/LibraryManagementApp/Dtos/PublisherDto.cs
new file mode 100644
index 0000000..e701323
--- /dev/null
+++ b/LibraryManagementApp/Dtos/PublisherDto.cs
@@ -0,0 +1,10 @@
+namespace LibraryManagementApp.Dtos;
+
+public record PublisherDto
+{
+ public Guid Id { get; init; }
+ public string Name{get; init;}
+ public string LogoUrl{get; init;}
+ public int? TotalAuthors { get; init; }
+ public int? TotalBooks { get; init; }
+}
\ No newline at end of file
diff --git a/LibraryManagementApp/Exceptions/NotFoundException.cs b/LibraryManagementApp/Exceptions/NotFoundException.cs
new file mode 100644
index 0000000..fcdabbe
--- /dev/null
+++ b/LibraryManagementApp/Exceptions/NotFoundException.cs
@@ -0,0 +1,24 @@
+namespace LibraryManagementApp.Exceptions;
+
+public class NotFoundException : Exception
+{
+ public NotFoundException()
+ : base()
+ {
+ }
+
+ public NotFoundException(string message)
+ : base(message)
+ {
+ }
+
+ public NotFoundException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public NotFoundException(string name, object key)
+ : base($"Entity \"{name}\" ({key}) was not found.")
+ {
+ }
+}
diff --git a/LibraryManagementApp/LibraryManagementApp.csproj b/LibraryManagementApp/LibraryManagementApp.csproj
new file mode 100644
index 0000000..5e13825
--- /dev/null
+++ b/LibraryManagementApp/LibraryManagementApp.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
diff --git a/LibraryManagementApp/Migrations/20230309042120_Initial.Designer.cs b/LibraryManagementApp/Migrations/20230309042120_Initial.Designer.cs
new file mode 100644
index 0000000..bacd982
--- /dev/null
+++ b/LibraryManagementApp/Migrations/20230309042120_Initial.Designer.cs
@@ -0,0 +1,262 @@
+//
+using System;
+using LibraryManagementApp.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace LibraryManagementApp.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20230309042120_Initial")]
+ partial class Initial
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("BookCategory", b =>
+ {
+ b.Property("BooksId")
+ .HasColumnType("uuid");
+
+ b.Property("CategoryId")
+ .HasColumnType("uuid");
+
+ b.HasKey("BooksId", "CategoryId");
+
+ b.HasIndex("CategoryId");
+
+ b.ToTable("BookCategory");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Author", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AvatarUrl")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PublisherId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.ToTable("Authors");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Book", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AuthorId")
+ .HasColumnType("uuid");
+
+ b.Property("CopyrightNotice")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ISBN")
+ .HasColumnType("integer");
+
+ b.Property("Language")
+ .HasColumnType("integer");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PageLength")
+ .HasColumnType("integer");
+
+ b.Property("PublisherId")
+ .HasColumnType("uuid");
+
+ b.Property("ReleaseYear")
+ .HasColumnType("date");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorId");
+
+ b.HasIndex("PublisherId");
+
+ b.ToTable("Books");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Category", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Categories");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Publisher", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LogoUrl")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Publishers");
+ });
+
+ modelBuilder.Entity("BookCategory", b =>
+ {
+ b.HasOne("LibraryManagementApp.Domain.Book", null)
+ .WithMany()
+ .HasForeignKey("BooksId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LibraryManagementApp.Domain.Category", null)
+ .WithMany()
+ .HasForeignKey("CategoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Book", b =>
+ {
+ b.HasOne("LibraryManagementApp.Domain.Author", "Author")
+ .WithMany("Books")
+ .HasForeignKey("AuthorId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LibraryManagementApp.Domain.Publisher", null)
+ .WithMany("Books")
+ .HasForeignKey("PublisherId");
+
+ b.Navigation("Author");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Author", b =>
+ {
+ b.Navigation("Books");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Publisher", b =>
+ {
+ b.Navigation("Books");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/LibraryManagementApp/Migrations/20230309042120_Initial.cs b/LibraryManagementApp/Migrations/20230309042120_Initial.cs
new file mode 100644
index 0000000..af9489d
--- /dev/null
+++ b/LibraryManagementApp/Migrations/20230309042120_Initial.cs
@@ -0,0 +1,168 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace LibraryManagementApp.Migrations
+{
+ ///
+ public partial class Initial : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Authors",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ FirstName = table.Column(type: "text", nullable: false),
+ LastName = table.Column(type: "text", nullable: false),
+ AvatarUrl = table.Column(type: "text", nullable: false),
+ PublisherId = table.Column(type: "uuid", nullable: false),
+ CreatedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ CreatedBy = table.Column(type: "uuid", nullable: false),
+ ModifiedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ ModifiedBy = table.Column(type: "uuid", nullable: false),
+ DeletedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ DeletedBy = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Authors", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Categories",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ Description = table.Column(type: "text", nullable: false),
+ CreatedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ CreatedBy = table.Column(type: "uuid", nullable: false),
+ ModifiedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ ModifiedBy = table.Column(type: "uuid", nullable: false),
+ DeletedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ DeletedBy = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Categories", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Publishers",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ LogoUrl = table.Column(type: "text", nullable: false),
+ CreatedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ CreatedBy = table.Column(type: "uuid", nullable: false),
+ ModifiedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ ModifiedBy = table.Column(type: "uuid", nullable: false),
+ DeletedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ DeletedBy = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Publishers", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Books",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Title = table.Column(type: "text", nullable: false),
+ CopyrightNotice = table.Column(type: "text", nullable: false),
+ ISBN = table.Column(type: "integer", nullable: false),
+ AuthorId = table.Column(type: "uuid", nullable: false),
+ PageLength = table.Column(type: "integer", nullable: false),
+ Language = table.Column(type: "integer", nullable: false),
+ ReleaseYear = table.Column(type: "date", nullable: false),
+ PublisherId = table.Column(type: "uuid", nullable: true),
+ CreatedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ CreatedBy = table.Column(type: "uuid", nullable: false),
+ ModifiedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ ModifiedBy = table.Column(type: "uuid", nullable: false),
+ DeletedOn = table.Column(type: "timestamp with time zone", nullable: false),
+ DeletedBy = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Books", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Books_Authors_AuthorId",
+ column: x => x.AuthorId,
+ principalTable: "Authors",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Books_Publishers_PublisherId",
+ column: x => x.PublisherId,
+ principalTable: "Publishers",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "BookCategory",
+ columns: table => new
+ {
+ BooksId = table.Column(type: "uuid", nullable: false),
+ CategoryId = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BookCategory", x => new { x.BooksId, x.CategoryId });
+ table.ForeignKey(
+ name: "FK_BookCategory_Books_BooksId",
+ column: x => x.BooksId,
+ principalTable: "Books",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_BookCategory_Categories_CategoryId",
+ column: x => x.CategoryId,
+ principalTable: "Categories",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BookCategory_CategoryId",
+ table: "BookCategory",
+ column: "CategoryId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Books_AuthorId",
+ table: "Books",
+ column: "AuthorId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Books_PublisherId",
+ table: "Books",
+ column: "PublisherId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "BookCategory");
+
+ migrationBuilder.DropTable(
+ name: "Books");
+
+ migrationBuilder.DropTable(
+ name: "Categories");
+
+ migrationBuilder.DropTable(
+ name: "Authors");
+
+ migrationBuilder.DropTable(
+ name: "Publishers");
+ }
+ }
+}
diff --git a/LibraryManagementApp/Migrations/ApplicationDbContextModelSnapshot.cs b/LibraryManagementApp/Migrations/ApplicationDbContextModelSnapshot.cs
new file mode 100644
index 0000000..d011046
--- /dev/null
+++ b/LibraryManagementApp/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -0,0 +1,259 @@
+//
+using System;
+using LibraryManagementApp.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace LibraryManagementApp.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ partial class ApplicationDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("BookCategory", b =>
+ {
+ b.Property("BooksId")
+ .HasColumnType("uuid");
+
+ b.Property("CategoryId")
+ .HasColumnType("uuid");
+
+ b.HasKey("BooksId", "CategoryId");
+
+ b.HasIndex("CategoryId");
+
+ b.ToTable("BookCategory");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Author", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AvatarUrl")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PublisherId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.ToTable("Authors");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Book", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AuthorId")
+ .HasColumnType("uuid");
+
+ b.Property("CopyrightNotice")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ISBN")
+ .HasColumnType("integer");
+
+ b.Property("Language")
+ .HasColumnType("integer");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PageLength")
+ .HasColumnType("integer");
+
+ b.Property("PublisherId")
+ .HasColumnType("uuid");
+
+ b.Property("ReleaseYear")
+ .HasColumnType("date");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorId");
+
+ b.HasIndex("PublisherId");
+
+ b.ToTable("Books");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Category", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Categories");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Publisher", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedBy")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeletedBy")
+ .HasColumnType("uuid");
+
+ b.Property("DeletedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LogoUrl")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedOn")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Publishers");
+ });
+
+ modelBuilder.Entity("BookCategory", b =>
+ {
+ b.HasOne("LibraryManagementApp.Domain.Book", null)
+ .WithMany()
+ .HasForeignKey("BooksId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LibraryManagementApp.Domain.Category", null)
+ .WithMany()
+ .HasForeignKey("CategoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Book", b =>
+ {
+ b.HasOne("LibraryManagementApp.Domain.Author", "Author")
+ .WithMany("Books")
+ .HasForeignKey("AuthorId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LibraryManagementApp.Domain.Publisher", null)
+ .WithMany("Books")
+ .HasForeignKey("PublisherId");
+
+ b.Navigation("Author");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Author", b =>
+ {
+ b.Navigation("Books");
+ });
+
+ modelBuilder.Entity("LibraryManagementApp.Domain.Publisher", b =>
+ {
+ b.Navigation("Books");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/LibraryManagementApp/Persistence/ApplicationDbContext.cs b/LibraryManagementApp/Persistence/ApplicationDbContext.cs
new file mode 100644
index 0000000..365bfea
--- /dev/null
+++ b/LibraryManagementApp/Persistence/ApplicationDbContext.cs
@@ -0,0 +1,26 @@
+using LibraryManagementApp.Domain;
+using LibraryManagementApp.Persistence.Configurations;
+using Microsoft.EntityFrameworkCore;
+
+namespace LibraryManagementApp.Persistence;
+
+public class ApplicationDbContext: DbContext
+{
+ public ApplicationDbContext(DbContextOptions options) : base(options)
+ {
+
+ }
+
+ public DbSet Authors => Set();
+ public DbSet Books => Set