From 97d2f0cb100ee688b139cfea9927a71f221be274 Mon Sep 17 00:00:00 2001 From: Ledana Date: Sat, 18 Apr 2026 19:55:30 +0200 Subject: [PATCH 01/10] Added my project --- PhoneBook/.gitattributes | 63 +++ PhoneBook/.gitignore | 363 ++++++++++++++++++ PhoneBook/PhoneBook.Ledana/ContactContext.cs | 167 ++++++++ .../Controllers/CategoryController.cs | 37 ++ .../Controllers/ContactController.cs | 43 +++ .../Controllers/EmailController.cs | 23 ++ .../Controllers/SMSController.cs | 24 ++ PhoneBook/PhoneBook.Ledana/Enums.cs | 47 +++ PhoneBook/PhoneBook.Ledana/InputValidator.cs | 44 +++ .../20260417151118_InitialCreate.Designer.cs | 58 +++ .../20260417151118_InitialCreate.cs | 37 ++ ...1_AddedUniquenessToPhoneNumber.Designer.cs | 61 +++ ...0417155211_AddedUniquenessToPhoneNumber.cs | 44 +++ ...18062517_AddedEmailSMSCategory.Designer.cs | 289 ++++++++++++++ .../20260418062517_AddedEmailSMSCategory.cs | 198 ++++++++++ ...20260418062659_AddedCategories.Designer.cs | 289 ++++++++++++++ .../20260418062659_AddedCategories.cs | 68 ++++ .../Migrations/ContactContextModelSnapshot.cs | 286 ++++++++++++++ PhoneBook/PhoneBook.Ledana/Models/Category.cs | 13 + PhoneBook/PhoneBook.Ledana/Models/Contact.cs | 21 + PhoneBook/PhoneBook.Ledana/Models/Email.cs | 15 + PhoneBook/PhoneBook.Ledana/Models/SMS.cs | 14 + .../PhoneBook.Ledana/PhoneBook.Ledana.csproj | 30 ++ .../PhoneBook.Ledana/PhoneBook.Ledana.slnx | 4 + PhoneBook/PhoneBook.Ledana/Program.cs | 7 + .../Properties/launchSettings.json | 8 + .../Services/CategoryServices.cs | 66 ++++ .../Services/ContactService.cs | 92 +++++ .../PhoneBook.Ledana/Services/EmailService.cs | 31 ++ .../PhoneBook.Ledana/Services/SMSService.cs | 31 ++ PhoneBook/PhoneBook.Ledana/UserInterface.cs | 270 +++++++++++++ PhoneBook/PhoneBook.Ledana/appSettings.json | 5 + .../InputValidatorTests.cs | 81 ++++ .../PhoneBookTests.Ledana.csproj | 27 ++ PhoneBook/README.md | 46 +++ 35 files changed, 2902 insertions(+) create mode 100644 PhoneBook/.gitattributes create mode 100644 PhoneBook/.gitignore create mode 100644 PhoneBook/PhoneBook.Ledana/ContactContext.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Enums.cs create mode 100644 PhoneBook/PhoneBook.Ledana/InputValidator.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.Designer.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.Designer.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.Designer.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.Designer.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Migrations/ContactContextModelSnapshot.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Models/Category.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Models/Contact.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Models/Email.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Models/SMS.cs create mode 100644 PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.csproj create mode 100644 PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.slnx create mode 100644 PhoneBook/PhoneBook.Ledana/Program.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Properties/launchSettings.json create mode 100644 PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Services/ContactService.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Services/EmailService.cs create mode 100644 PhoneBook/PhoneBook.Ledana/Services/SMSService.cs create mode 100644 PhoneBook/PhoneBook.Ledana/UserInterface.cs create mode 100644 PhoneBook/PhoneBook.Ledana/appSettings.json create mode 100644 PhoneBook/PhoneBookTests.Ledana/InputValidatorTests.cs create mode 100644 PhoneBook/PhoneBookTests.Ledana/PhoneBookTests.Ledana.csproj create mode 100644 PhoneBook/README.md diff --git a/PhoneBook/.gitattributes b/PhoneBook/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/PhoneBook/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/PhoneBook/.gitignore b/PhoneBook/.gitignore new file mode 100644 index 00000000..9491a2fd --- /dev/null +++ b/PhoneBook/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/PhoneBook/PhoneBook.Ledana/ContactContext.cs b/PhoneBook/PhoneBook.Ledana/ContactContext.cs new file mode 100644 index 00000000..89cbd483 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/ContactContext.cs @@ -0,0 +1,167 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using PhoneBook.Ledana.Models; + +namespace PhoneBook.Ledana +{ + internal class ContactContext : DbContext + { + public DbSet Contacts { get; set; } + public DbSet Emails { get; set; } + public DbSet SMSs { get; set; } + public DbSet Categories { get; set; } + + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + // Load configuration from appsettings.json + var config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appSettings.json", optional: false, reloadOnChange: true) + .Build(); + + var connectionString = config.GetConnectionString("ContactsDb"); + + optionsBuilder.UseSqlServer(connectionString) + .EnableSensitiveDataLogging() + .UseLoggerFactory(GetLoggerFactory()); + } + private ILoggerFactory? GetLoggerFactory() + { + var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddConsole(); + builder.AddFilter((category, level) => + category == DbLoggerCategory.Database.Command.Name && + level == LogLevel.Information); + }); + return loggerFactory; + } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasData(new List + { + new() { + Id = 1, + FirstName = "Bob", + LastName = "Dylan", + Email = "dylan12@abc.com", + PhoneNumber = "+355691234567", + CategoryId = 1 + }, + new() { + Id = 2, + FirstName = "Amelia", + LastName = "Aster", + Email = "aster12@abc.com", + PhoneNumber = "+355691234123", + CategoryId = 2 + }, + new() { + Id = 3, + FirstName = "Loredana", + LastName = "Marti", + Email = "marti12@abc.com", + PhoneNumber = "+355694564567", + CategoryId = 1 + }, + new() { + Id = 4, + FirstName = "Luiza", + LastName = "Griffin", + Email = "griffin12@abc.com", + PhoneNumber = "+355691201467", + CategoryId = 3 + }, + new() { + Id = 5, + FirstName = "Daniel", + LastName = "Scott", + Email = "scott12@abc.com", + PhoneNumber = "+355690230123", + CategoryId = 3 + }, + new() { + Id = 6, + FirstName = "Vivian", + LastName = "DeMarti", + Email = "demarti12@abc.com", + PhoneNumber = "+355694064061", + CategoryId = 1 + } + }); + modelBuilder.Entity() + .HasData(new List + { + new() + { + Id = 1, + Name = "Family" + }, + new() + { + Id = 2, + Name = "Friends" + }, + new() + { + Id = 3, + Name = "Work" + } + }); + + modelBuilder.Entity() + .HasData(new List + { + new() + { + Id = 1, + Subject = "Urgent", + Body = "Please call me ASAP", + ContactId = 4 + }, + new() + { + Id = 2, + Subject = "Party time", + Body = "When should we be at the party?", + ContactId = 1 + }, + new() + { + Id = 3, + Subject = "Project boy", + Body = "We will have a meeting about the project Friday at noon", + ContactId = 2 + } + }); + + modelBuilder.Entity() + .HasData(new List + { + new() + { + Id = 1, + Subject = "Call me when you can", + ContactId = 3 + }, + new() + { + Id = 2, + Subject = "I just left work, I'll be home in 10", + ContactId = 2 + }, + new() + { + Id = 3, + Subject = "Stop calling me!!!! :)", + ContactId = 5 + } + }); + } + } + + +} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs new file mode 100644 index 00000000..a2a3d86b --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore; +using PhoneBook.Ledana.Models; + +namespace PhoneBook.Ledana.Controllers +{ + internal class CategoryController + { + internal static List GetCategories() + { + using var context = new ContactContext(); + var categories = context.Categories + .Include(c => c.Contacts) + .ToList(); + return categories; + } + internal static void AddCategory(Category category) + { + using var context = new ContactContext(); + context.Categories.Add(category); + context.SaveChanges(); + } + + internal static void DeleteCategory(Category category) + { + using var context = new ContactContext(); + context.Categories.Remove(category); + context.SaveChanges(); + } + + internal static void UpdateCategory(Category category) + { + using var context = new ContactContext(); + context.Categories.Update(category); + context.SaveChanges(); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs new file mode 100644 index 00000000..a64ab538 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore; +using PhoneBook.Ledana.Models; + +namespace PhoneBook.Ledana.Controllers +{ + internal class ContactController + { + internal static void AddContact(Contact contact) + { + using var context = new ContactContext(); + context.Contacts.Add(contact); + context.SaveChanges(); + } + + internal static void DeleteContact(Contact contact) + { + using var context = new ContactContext(); + context.Contacts.Remove(contact); + context.SaveChanges(); + } + + internal static List GetAllContacts() + { + using var context = new ContactContext(); + var contacts = context.Contacts.Include(c => c.Category) + .ToList(); + return contacts; + } + + internal static void UpdateContact(Contact contact) + { + using var context = new ContactContext(); + context.Contacts.Update(contact); + context.SaveChanges(); + } + internal static bool ValidatePhoneNumber(string phoneNumber) + { + using var context = new ContactContext(); + var phoneNumberExists = context.Contacts.Where(c => c.PhoneNumber == phoneNumber).Count(); + return phoneNumberExists > 0; + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs new file mode 100644 index 00000000..c09b77d8 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore; +using PhoneBook.Ledana.Models; + +namespace PhoneBook.Ledana.Controllers +{ + internal class EmailController + { + internal static void SendEmail(Email email) + { + using var context = new ContactContext(); + context.Emails.Add(email); + context.SaveChanges(); + } + internal static List GetEmails() + { + using var context = new ContactContext(); + var emails = context.Emails + .Include(e => e.Contact) + .ToList(); + return emails; + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs new file mode 100644 index 00000000..601425e8 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore; +using PhoneBook.Ledana.Models; + +namespace PhoneBook.Ledana.Controllers +{ + internal class SMSController + { + internal static List GetSMS() + { + using var context = new ContactContext(); + var SMSs = context.SMSs + .Include(s => s.Contact) + .ToList(); + return SMSs; + } + + internal static void SendSMS(SMS sms) + { + using var context = new ContactContext(); + context.SMSs.Add(sms); + context.SaveChanges(); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Enums.cs b/PhoneBook/PhoneBook.Ledana/Enums.cs new file mode 100644 index 00000000..cb8dd89c --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Enums.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PhoneBook.Ledana +{ + internal class Enums + { + internal enum MenuOptions + { + ManageContacts, + ManageCategories, + ManageEmails, + ManageSMSs, + Quit + } + internal enum ContactOptions + { + AddContact, + DeleteContact, + UpdateContact, + ViewContact, + ViewAllContacts, + GoBack + } + internal enum CategoryOptions + { + AddCategory, + DeleteCategory, + UpdateCategory, + ViewCategories, + GoBack + } + internal enum EmailOptions + { + SendEmail, + ViewEmails, + GoBack + } + internal enum SMSOptions + { + SendSMS, + ViewSMSs, + GoBack + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/InputValidator.cs b/PhoneBook/PhoneBook.Ledana/InputValidator.cs new file mode 100644 index 00000000..6525ad8c --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/InputValidator.cs @@ -0,0 +1,44 @@ +using PhoneBook.Ledana.Controllers; +using Spectre.Console; +using System.Text.RegularExpressions; + +namespace PhoneBook.Ledana +{ + public static class InputValidator + { + public static string ValidateEmail() + { + var email = AnsiConsole.Ask("Contact's email address(abc@abc.com):"); + + while (!IsEmailValid(email)) + { + email = AnsiConsole.Ask("Invalid email, contact's email address(abc@abc.com):"); + } + return email; + } + public static bool IsEmailValid(string email) + { + return Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"); + } + public static string ValidatePhoneNumber() + { + var phoneNumber = AnsiConsole.Ask("Contact's phone number(+3556********):"); + + while ((!IsNumberValid(phoneNumber))|| ContactController.ValidatePhoneNumber(phoneNumber)) + { + if (ContactController.ValidatePhoneNumber(phoneNumber)) + phoneNumber = AnsiConsole.Ask("Phone number already exist, try again(+3556********):"); + else + phoneNumber = AnsiConsole.Ask("Invalid phone number format, try again(+3556********):"); + } + return phoneNumber; + } + public static bool IsNumberValid(string phoneNumber) + { + return phoneNumber.Length == 13 + && phoneNumber.StartsWith('+') + && phoneNumber.Substring(1).All(char.IsDigit); + //&& !ContactController.ValidatePhoneNumber(phoneNumber); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.Designer.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.Designer.cs new file mode 100644 index 00000000..9b9c6c03 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.Designer.cs @@ -0,0 +1,58 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PhoneBook.Ledana; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + [DbContext(typeof(ContactContext))] + [Migration("20260417151118_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Contacts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.cs new file mode 100644 index 00000000..99f2a9f7 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260417151118_InitialCreate.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Contacts", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FirstName = table.Column(type: "nvarchar(max)", nullable: false), + LastName = table.Column(type: "nvarchar(max)", nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: false), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Contacts", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Contacts"); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.Designer.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.Designer.cs new file mode 100644 index 00000000..d343e06c --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.Designer.cs @@ -0,0 +1,61 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PhoneBook.Ledana; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + [DbContext(typeof(ContactContext))] + [Migration("20260417155211_AddedUniquenessToPhoneNumber")] + partial class AddedUniquenessToPhoneNumber + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Contacts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.cs new file mode 100644 index 00000000..c1a624c7 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260417155211_AddedUniquenessToPhoneNumber.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + /// + public partial class AddedUniquenessToPhoneNumber : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "PhoneNumber", + table: "Contacts", + type: "nvarchar(450)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)"); + + migrationBuilder.CreateIndex( + name: "IX_Contacts_PhoneNumber", + table: "Contacts", + column: "PhoneNumber", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Contacts_PhoneNumber", + table: "Contacts"); + + migrationBuilder.AlterColumn( + name: "PhoneNumber", + table: "Contacts", + type: "nvarchar(max)", + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(450)"); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.Designer.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.Designer.cs new file mode 100644 index 00000000..a51494be --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.Designer.cs @@ -0,0 +1,289 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PhoneBook.Ledana; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + [DbContext(typeof(ContactContext))] + [Migration("20260418062517_AddedEmailSMSCategory")] + partial class AddedEmailSMSCategory + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Category"); + + b.HasData( + new + { + Id = 1, + Name = "Family" + }, + new + { + Id = 2, + Name = "Friends" + }, + new + { + Id = 3, + Name = "Work" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Contacts"); + + b.HasData( + new + { + Id = 1, + CategoryId = 1, + Email = "dylan12@abc.com", + FirstName = "Bob", + LastName = "Dylan", + PhoneNumber = "+355691234567" + }, + new + { + Id = 2, + CategoryId = 2, + Email = "aster12@abc.com", + FirstName = "Amelia", + LastName = "Aster", + PhoneNumber = "+355691234123" + }, + new + { + Id = 3, + CategoryId = 1, + Email = "marti12@abc.com", + FirstName = "Loredana", + LastName = "Marti", + PhoneNumber = "+355694564567" + }, + new + { + Id = 4, + CategoryId = 3, + Email = "griffin12@abc.com", + FirstName = "Luiza", + LastName = "Griffin", + PhoneNumber = "+355691201467" + }, + new + { + Id = 5, + CategoryId = 3, + Email = "scott12@abc.com", + FirstName = "Daniel", + LastName = "Scott", + PhoneNumber = "+355690230123" + }, + new + { + Id = 6, + CategoryId = 1, + Email = "demarti12@abc.com", + FirstName = "Vivian", + LastName = "DeMarti", + PhoneNumber = "+355694064061" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Email", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactId") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("Emails"); + + b.HasData( + new + { + Id = 1, + Body = "Please call me ASAP", + ContactId = 4, + Subject = "Urgent" + }, + new + { + Id = 2, + Body = "When should we be at the party?", + ContactId = 1, + Subject = "Party time" + }, + new + { + Id = 3, + Body = "We will have a meeting about the project Friday at noon", + ContactId = 2, + Subject = "Project boy" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.SMS", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("SMSs"); + + b.HasData( + new + { + Id = 1, + ContactId = 3, + Subject = "Call me when you can" + }, + new + { + Id = 2, + ContactId = 2, + Subject = "I just left work, I'll be home in 10" + }, + new + { + Id = 3, + ContactId = 5, + Subject = "Stop calling me!!!! :)" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.HasOne("PhoneBook.Ledana.Models.Category", "Category") + .WithMany("Contacts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Email", b => + { + b.HasOne("PhoneBook.Ledana.Models.Contact", "Contact") + .WithMany("Emails") + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.SMS", b => + { + b.HasOne("PhoneBook.Ledana.Models.Contact", "Contact") + .WithMany("SMSs") + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Category", b => + { + b.Navigation("Contacts"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Navigation("Emails"); + + b.Navigation("SMSs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.cs new file mode 100644 index 00000000..5f98e54d --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062517_AddedEmailSMSCategory.cs @@ -0,0 +1,198 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace PhoneBook.Ledana.Migrations +{ + /// + public partial class AddedEmailSMSCategory : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CategoryId", + table: "Contacts", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "Category", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Category", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Emails", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Subject = table.Column(type: "nvarchar(max)", nullable: true), + Body = table.Column(type: "nvarchar(max)", nullable: true), + ContactId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Emails", x => x.Id); + table.ForeignKey( + name: "FK_Emails_Contacts_ContactId", + column: x => x.ContactId, + principalTable: "Contacts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SMSs", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Subject = table.Column(type: "nvarchar(max)", nullable: true), + ContactId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SMSs", x => x.Id); + table.ForeignKey( + name: "FK_SMSs_Contacts_ContactId", + column: x => x.ContactId, + principalTable: "Contacts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + table: "Category", + columns: new[] { "Id", "Name" }, + values: new object[,] + { + { 1, "Family" }, + { 2, "Friends" }, + { 3, "Work" } + }); + + migrationBuilder.InsertData( + table: "Contacts", + columns: new[] { "Id", "CategoryId", "Email", "FirstName", "LastName", "PhoneNumber" }, + values: new object[,] + { + { 1, 1, "dylan12@abc.com", "Bob", "Dylan", "+355691234567" }, + { 2, 2, "aster12@abc.com", "Amelia", "Aster", "+355691234123" }, + { 3, 1, "marti12@abc.com", "Loredana", "Marti", "+355694564567" }, + { 4, 3, "griffin12@abc.com", "Luiza", "Griffin", "+355691201467" }, + { 5, 3, "scott12@abc.com", "Daniel", "Scott", "+355690230123" }, + { 6, 1, "demarti12@abc.com", "Vivian", "DeMarti", "+355694064061" } + }); + + migrationBuilder.InsertData( + table: "Emails", + columns: new[] { "Id", "Body", "ContactId", "Subject" }, + values: new object[,] + { + { 1, "Please call me ASAP", 4, "Urgent" }, + { 2, "When should we be at the party?", 1, "Party time" }, + { 3, "We will have a meeting about the project Friday at noon", 2, "Project boy" } + }); + + migrationBuilder.InsertData( + table: "SMSs", + columns: new[] { "Id", "ContactId", "Subject" }, + values: new object[,] + { + { 1, 3, "Call me when you can" }, + { 2, 2, "I just left work, I'll be home in 10" }, + { 3, 5, "Stop calling me!!!! :)" } + }); + + migrationBuilder.CreateIndex( + name: "IX_Contacts_CategoryId", + table: "Contacts", + column: "CategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_Emails_ContactId", + table: "Emails", + column: "ContactId"); + + migrationBuilder.CreateIndex( + name: "IX_SMSs_ContactId", + table: "SMSs", + column: "ContactId"); + + migrationBuilder.AddForeignKey( + name: "FK_Contacts_Category_CategoryId", + table: "Contacts", + column: "CategoryId", + principalTable: "Category", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Contacts_Category_CategoryId", + table: "Contacts"); + + migrationBuilder.DropTable( + name: "Category"); + + migrationBuilder.DropTable( + name: "Emails"); + + migrationBuilder.DropTable( + name: "SMSs"); + + migrationBuilder.DropIndex( + name: "IX_Contacts_CategoryId", + table: "Contacts"); + + migrationBuilder.DeleteData( + table: "Contacts", + keyColumn: "Id", + keyValue: 1); + + migrationBuilder.DeleteData( + table: "Contacts", + keyColumn: "Id", + keyValue: 2); + + migrationBuilder.DeleteData( + table: "Contacts", + keyColumn: "Id", + keyValue: 3); + + migrationBuilder.DeleteData( + table: "Contacts", + keyColumn: "Id", + keyValue: 4); + + migrationBuilder.DeleteData( + table: "Contacts", + keyColumn: "Id", + keyValue: 5); + + migrationBuilder.DeleteData( + table: "Contacts", + keyColumn: "Id", + keyValue: 6); + + migrationBuilder.DropColumn( + name: "CategoryId", + table: "Contacts"); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.Designer.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.Designer.cs new file mode 100644 index 00000000..e7f5e0d5 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.Designer.cs @@ -0,0 +1,289 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PhoneBook.Ledana; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + [DbContext(typeof(ContactContext))] + [Migration("20260418062659_AddedCategories")] + partial class AddedCategories + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + + b.HasData( + new + { + Id = 1, + Name = "Family" + }, + new + { + Id = 2, + Name = "Friends" + }, + new + { + Id = 3, + Name = "Work" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Contacts"); + + b.HasData( + new + { + Id = 1, + CategoryId = 1, + Email = "dylan12@abc.com", + FirstName = "Bob", + LastName = "Dylan", + PhoneNumber = "+355691234567" + }, + new + { + Id = 2, + CategoryId = 2, + Email = "aster12@abc.com", + FirstName = "Amelia", + LastName = "Aster", + PhoneNumber = "+355691234123" + }, + new + { + Id = 3, + CategoryId = 1, + Email = "marti12@abc.com", + FirstName = "Loredana", + LastName = "Marti", + PhoneNumber = "+355694564567" + }, + new + { + Id = 4, + CategoryId = 3, + Email = "griffin12@abc.com", + FirstName = "Luiza", + LastName = "Griffin", + PhoneNumber = "+355691201467" + }, + new + { + Id = 5, + CategoryId = 3, + Email = "scott12@abc.com", + FirstName = "Daniel", + LastName = "Scott", + PhoneNumber = "+355690230123" + }, + new + { + Id = 6, + CategoryId = 1, + Email = "demarti12@abc.com", + FirstName = "Vivian", + LastName = "DeMarti", + PhoneNumber = "+355694064061" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Email", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactId") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("Emails"); + + b.HasData( + new + { + Id = 1, + Body = "Please call me ASAP", + ContactId = 4, + Subject = "Urgent" + }, + new + { + Id = 2, + Body = "When should we be at the party?", + ContactId = 1, + Subject = "Party time" + }, + new + { + Id = 3, + Body = "We will have a meeting about the project Friday at noon", + ContactId = 2, + Subject = "Project boy" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.SMS", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("SMSs"); + + b.HasData( + new + { + Id = 1, + ContactId = 3, + Subject = "Call me when you can" + }, + new + { + Id = 2, + ContactId = 2, + Subject = "I just left work, I'll be home in 10" + }, + new + { + Id = 3, + ContactId = 5, + Subject = "Stop calling me!!!! :)" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.HasOne("PhoneBook.Ledana.Models.Category", "Category") + .WithMany("Contacts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Email", b => + { + b.HasOne("PhoneBook.Ledana.Models.Contact", "Contact") + .WithMany("Emails") + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.SMS", b => + { + b.HasOne("PhoneBook.Ledana.Models.Contact", "Contact") + .WithMany("SMSs") + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Category", b => + { + b.Navigation("Contacts"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Navigation("Emails"); + + b.Navigation("SMSs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.cs b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.cs new file mode 100644 index 00000000..13094b58 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/20260418062659_AddedCategories.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + /// + public partial class AddedCategories : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Contacts_Category_CategoryId", + table: "Contacts"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Category", + table: "Category"); + + migrationBuilder.RenameTable( + name: "Category", + newName: "Categories"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Categories", + table: "Categories", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Contacts_Categories_CategoryId", + table: "Contacts", + column: "CategoryId", + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Contacts_Categories_CategoryId", + table: "Contacts"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Categories", + table: "Categories"); + + migrationBuilder.RenameTable( + name: "Categories", + newName: "Category"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Category", + table: "Category", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Contacts_Category_CategoryId", + table: "Contacts", + column: "CategoryId", + principalTable: "Category", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Migrations/ContactContextModelSnapshot.cs b/PhoneBook/PhoneBook.Ledana/Migrations/ContactContextModelSnapshot.cs new file mode 100644 index 00000000..f6aa653c --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Migrations/ContactContextModelSnapshot.cs @@ -0,0 +1,286 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PhoneBook.Ledana; + +#nullable disable + +namespace PhoneBook.Ledana.Migrations +{ + [DbContext(typeof(ContactContext))] + partial class ContactContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + + b.HasData( + new + { + Id = 1, + Name = "Family" + }, + new + { + Id = 2, + Name = "Friends" + }, + new + { + Id = 3, + Name = "Work" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("Contacts"); + + b.HasData( + new + { + Id = 1, + CategoryId = 1, + Email = "dylan12@abc.com", + FirstName = "Bob", + LastName = "Dylan", + PhoneNumber = "+355691234567" + }, + new + { + Id = 2, + CategoryId = 2, + Email = "aster12@abc.com", + FirstName = "Amelia", + LastName = "Aster", + PhoneNumber = "+355691234123" + }, + new + { + Id = 3, + CategoryId = 1, + Email = "marti12@abc.com", + FirstName = "Loredana", + LastName = "Marti", + PhoneNumber = "+355694564567" + }, + new + { + Id = 4, + CategoryId = 3, + Email = "griffin12@abc.com", + FirstName = "Luiza", + LastName = "Griffin", + PhoneNumber = "+355691201467" + }, + new + { + Id = 5, + CategoryId = 3, + Email = "scott12@abc.com", + FirstName = "Daniel", + LastName = "Scott", + PhoneNumber = "+355690230123" + }, + new + { + Id = 6, + CategoryId = 1, + Email = "demarti12@abc.com", + FirstName = "Vivian", + LastName = "DeMarti", + PhoneNumber = "+355694064061" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Email", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactId") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("Emails"); + + b.HasData( + new + { + Id = 1, + Body = "Please call me ASAP", + ContactId = 4, + Subject = "Urgent" + }, + new + { + Id = 2, + Body = "When should we be at the party?", + ContactId = 1, + Subject = "Party time" + }, + new + { + Id = 3, + Body = "We will have a meeting about the project Friday at noon", + ContactId = 2, + Subject = "Project boy" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.SMS", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContactId") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("SMSs"); + + b.HasData( + new + { + Id = 1, + ContactId = 3, + Subject = "Call me when you can" + }, + new + { + Id = 2, + ContactId = 2, + Subject = "I just left work, I'll be home in 10" + }, + new + { + Id = 3, + ContactId = 5, + Subject = "Stop calling me!!!! :)" + }); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.HasOne("PhoneBook.Ledana.Models.Category", "Category") + .WithMany("Contacts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Email", b => + { + b.HasOne("PhoneBook.Ledana.Models.Contact", "Contact") + .WithMany("Emails") + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.SMS", b => + { + b.HasOne("PhoneBook.Ledana.Models.Contact", "Contact") + .WithMany("SMSs") + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Category", b => + { + b.Navigation("Contacts"); + }); + + modelBuilder.Entity("PhoneBook.Ledana.Models.Contact", b => + { + b.Navigation("Emails"); + + b.Navigation("SMSs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Models/Category.cs b/PhoneBook/PhoneBook.Ledana/Models/Category.cs new file mode 100644 index 00000000..b288f0e7 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Models/Category.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PhoneBook.Ledana.Models +{ + internal class Category + { + public int Id { get; set; } + public string Name { get; set; } = null!; + public List Contacts { get; set; } = []; + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Models/Contact.cs b/PhoneBook/PhoneBook.Ledana/Models/Contact.cs new file mode 100644 index 00000000..8ca028a8 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Models/Contact.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Text; + +namespace PhoneBook.Ledana.Models +{ + [Index(nameof(PhoneNumber), IsUnique = true)] + internal class Contact + { + public int Id { get; set; } + public string FirstName { get; set; } = null!; + public string LastName { get; set; } = null!; + public string Email { get; set; } = null!; + public string PhoneNumber { get; set; } = null!; + public int CategoryId { get; set; } + public Category? Category { get; set; } + public List Emails { get; set; } = []; + public List SMSs { get; set; } = []; + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Models/Email.cs b/PhoneBook/PhoneBook.Ledana/Models/Email.cs new file mode 100644 index 00000000..7f07f621 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Models/Email.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PhoneBook.Ledana.Models +{ + internal class Email + { + public int Id { get; set; } + public string? Subject { get; set; } + public string? Body { get; set; } + public int ContactId { get; set; } + public Contact? Contact { get; set; } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Models/SMS.cs b/PhoneBook/PhoneBook.Ledana/Models/SMS.cs new file mode 100644 index 00000000..76854e10 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Models/SMS.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PhoneBook.Ledana.Models +{ + internal class SMS + { + public int Id { get; set; } + public string? Subject { get; set; } + public int ContactId { get; set; } + public Contact? Contact { get; set; } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.csproj b/PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.csproj new file mode 100644 index 00000000..4f86ed13 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.csproj @@ -0,0 +1,30 @@ + + + + Exe + net10.0 + enable + enable + + + + + Always + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.slnx b/PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.slnx new file mode 100644 index 00000000..d723f12f --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/PhoneBook.Ledana.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/PhoneBook/PhoneBook.Ledana/Program.cs b/PhoneBook/PhoneBook.Ledana/Program.cs new file mode 100644 index 00000000..c135309e --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Program.cs @@ -0,0 +1,7 @@ +using PhoneBook.Ledana; + +var context = new ContactContext(); +context.Database.EnsureDeleted(); +context.Database.EnsureCreated(); +UserInterface.MainMenu(); + diff --git a/PhoneBook/PhoneBook.Ledana/Properties/launchSettings.json b/PhoneBook/PhoneBook.Ledana/Properties/launchSettings.json new file mode 100644 index 00000000..fdc6b939 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "PhoneBook.Ledana": { + "commandName": "Project", + "workingDirectory": "C:\\Users\\ledan\\OneDrive\\Desktop\\ef\\PhoneBook\\PhoneBook.Ledana" + } + } +} \ No newline at end of file diff --git a/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs b/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs new file mode 100644 index 00000000..e295df79 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs @@ -0,0 +1,66 @@ +using PhoneBook.Ledana.Controllers; +using PhoneBook.Ledana.Models; +using Spectre.Console; + +namespace PhoneBook.Ledana.Services +{ + internal class CategoryServices + { + internal static void AddCategory() + { + var category = new Category + { + Name = AnsiConsole.Ask("Category's name:") + }; + CategoryController.AddCategory(category); + } + + internal static void DeleteCategory() + { + Category category = GetCategoryOptionInput(); + if (category is null) + { + Console.WriteLine("Empty contact"); + return; + } + CategoryController.DeleteCategory(category); + } + + internal static Category GetCategoryOptionInput() + { + List categories = CategoryController.GetCategories(); + if (categories.Count == 0) + { + Console.WriteLine("Categories list is empty"); + return null; + } + var categoriesArray = categories.Select(c => c.Name).ToArray(); + var option = AnsiConsole.Prompt(new SelectionPrompt() + .Title("Choose category") + .AddChoices(categoriesArray)); + var category = categories.SingleOrDefault(c => c.Name == option); + return category; + } + + internal static void UpdateCategory() + { + var category = GetCategoryOptionInput(); + if (category is null) + { + Console.WriteLine("Empty contact"); + return; + } + category.Name = AnsiConsole.Confirm("Update First Name?") + ? AnsiConsole.Ask("Contact's new first name") + : category.Name; + + CategoryController.UpdateCategory(category); + } + + internal static void ViewCategories() + { + var categories = CategoryController.GetCategories(); + UserInterface.ViewCategories(categories); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs b/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs new file mode 100644 index 00000000..37551029 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs @@ -0,0 +1,92 @@ +using PhoneBook.Ledana.Controllers; +using PhoneBook.Ledana.Models; +using Spectre.Console; + +namespace PhoneBook.Ledana.Services +{ + internal class ContactService + { + internal static void AddContact() + { + var contact = new Contact + { + FirstName = AnsiConsole.Ask("Contact's first name:"), + LastName = AnsiConsole.Ask("Contact's last name:"), + Email = InputValidator.ValidateEmail(), + PhoneNumber = InputValidator.ValidatePhoneNumber() + }; + var category = CategoryServices.GetCategoryOptionInput(); + contact.CategoryId = category.Id; + ContactController.AddContact(contact); + } + + internal static void DeleteContact() + { + var contact = GetContactOptionInput(); + if (contact is null) + { + Console.WriteLine("Empty contact"); + return; + } + ContactController.DeleteContact(contact); + } + + internal static void UpdateContact() + { + var contact = GetContactOptionInput(); + if (contact is null) + { + Console.WriteLine("Empty contact"); + return; + } + contact.FirstName = AnsiConsole.Confirm("Update First Name?") + ? AnsiConsole.Ask("Contact's new first name") + : contact.FirstName; + contact.LastName = AnsiConsole.Confirm("Update Last Name?") + ? AnsiConsole.Ask("Contact's new last name") + : contact.LastName; + contact.Email = AnsiConsole.Confirm("Update Email?") + ? InputValidator.ValidateEmail() + : contact.Email; + contact.PhoneNumber = AnsiConsole.Confirm("Update Phone Number?") + ? InputValidator.ValidatePhoneNumber() + : contact.PhoneNumber; + var category = CategoryServices.GetCategoryOptionInput(); + contact.CategoryId = category.Id; + ContactController.UpdateContact(contact); + } + + internal static void ViewContact() + { + var contact = GetContactOptionInput(); + if (contact is null) + { + Console.WriteLine("Empty contact"); + return; + } + UserInterface.ViewContact(contact); + } + + internal static void ViewContacts() + { + var contacts = ContactController.GetAllContacts(); + UserInterface.ViewContacts(contacts); + } + + internal static Contact? GetContactOptionInput() + { + List contacts = ContactController.GetAllContacts(); + if (contacts.Count == 0) + { + Console.WriteLine("Contact list is empty"); + return null; + } + var contactsArray = contacts.Select(c => $"{c.FirstName} {c.LastName}").ToArray(); + var option = AnsiConsole.Prompt(new SelectionPrompt() + .Title("Choose contact") + .AddChoices(contactsArray)); + var contact = contacts.SingleOrDefault(c => $"{c.FirstName} {c.LastName}" == option); + return contact; + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs b/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs new file mode 100644 index 00000000..b3363a42 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs @@ -0,0 +1,31 @@ +using PhoneBook.Ledana.Controllers; +using PhoneBook.Ledana.Models; +using Spectre.Console; + +namespace PhoneBook.Ledana.Services +{ + internal class EmailService + { + internal static void SendEmail() + { + var email = new Email + { + Subject = AnsiConsole.Ask("Subject:"), + Body = AnsiConsole.Ask("Body:") + }; + var contact = ContactService.GetContactOptionInput(); + if (contact is null) + { + Console.WriteLine("Contact empty"); + return; + } + email.ContactId = contact.Id; + EmailController.SendEmail(email); + } + internal static void ViewEmails() + { + var emails = EmailController.GetEmails(); + UserInterface.ViewEmails(emails); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs b/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs new file mode 100644 index 00000000..f225bdad --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs @@ -0,0 +1,31 @@ +using PhoneBook.Ledana.Controllers; +using PhoneBook.Ledana.Models; +using Spectre.Console; + +namespace PhoneBook.Ledana.Services +{ + internal class SMSService + { + internal static void SendSMS() + { + var sms = new SMS + { + Subject = AnsiConsole.Ask("Subject:") + }; + var contact = ContactService.GetContactOptionInput(); + if (contact is null) + { + Console.WriteLine("Contact empty"); + return; + } + sms.ContactId = contact.Id; + SMSController.SendSMS(sms); + } + + internal static void ViewSMSs() + { + var SMSs = SMSController.GetSMS(); + UserInterface.ViewSMSs(SMSs); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/UserInterface.cs b/PhoneBook/PhoneBook.Ledana/UserInterface.cs new file mode 100644 index 00000000..a051996a --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/UserInterface.cs @@ -0,0 +1,270 @@ +using PhoneBook.Ledana.Models; +using PhoneBook.Ledana.Services; +using Spectre.Console; +using static PhoneBook.Ledana.Enums; + +namespace PhoneBook.Ledana +{ + internal class UserInterface + { + internal static void MainMenu() + { + var isAppRunning = true; + while (isAppRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + MenuOptions.ManageContacts, + MenuOptions.ManageCategories, + MenuOptions.ManageEmails, + MenuOptions.ManageSMSs, + MenuOptions.Quit)); + + switch (option) + { + case MenuOptions.ManageContacts: + ContactsMenu(); + break; + case MenuOptions.ManageCategories: + CategoriesMenu(); + break; + case MenuOptions.ManageEmails: + EmailsMenu(); + break; + case MenuOptions.ManageSMSs: + SMSsMenu(); + break; + case MenuOptions.Quit: + Console.WriteLine("Goodbye"); + isAppRunning = false; + break; + } + } + } + + private static void SMSsMenu() + { + var isSMSsMenuRunning = true; + while (isSMSsMenuRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + SMSOptions.SendSMS, + SMSOptions.ViewSMSs, + SMSOptions.GoBack + )); + + switch (option) + { + case SMSOptions.SendSMS: + SMSService.SendSMS(); + break; + case SMSOptions.ViewSMSs: + SMSService.ViewSMSs(); + break; + case SMSOptions.GoBack: + isSMSsMenuRunning = false; + break; + } + } + } + + private static void EmailsMenu() + { + var isEmailsMenuRunning = true; + while (isEmailsMenuRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + EmailOptions.SendEmail, + EmailOptions.ViewEmails, + EmailOptions.GoBack + )); + + switch (option) + { + case EmailOptions.SendEmail: + EmailService.SendEmail(); + break; + case EmailOptions.ViewEmails: + EmailService.ViewEmails(); + break; + case EmailOptions.GoBack: + isEmailsMenuRunning = false; + break; + } + } + } + + private static void CategoriesMenu() + { + var isCategoriesMenuRunning = true; + while (isCategoriesMenuRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + CategoryOptions.AddCategory, + CategoryOptions.DeleteCategory, + CategoryOptions.UpdateCategory, + CategoryOptions.ViewCategories, + CategoryOptions.GoBack + )); + + switch (option) + { + case CategoryOptions.AddCategory: + CategoryServices.AddCategory(); + break; + case CategoryOptions.DeleteCategory: + CategoryServices.DeleteCategory(); + break; + case CategoryOptions.UpdateCategory: + CategoryServices.UpdateCategory(); + break; + case CategoryOptions.ViewCategories: + CategoryServices.ViewCategories(); + break; + case CategoryOptions.GoBack: + isCategoriesMenuRunning = false; + break; + } + } + } + + private static void ContactsMenu() + { + var isContactsMenuRunning = true; + while (isContactsMenuRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + ContactOptions.AddContact, + ContactOptions.DeleteContact, + ContactOptions.UpdateContact, + ContactOptions.ViewContact, + ContactOptions.ViewAllContacts, + ContactOptions.GoBack + )); + + switch (option) + { + case ContactOptions.AddContact: + ContactService.AddContact(); + break; + case ContactOptions.DeleteContact: + ContactService.DeleteContact(); + break; + case ContactOptions.UpdateContact: + ContactService.UpdateContact(); + break; + case ContactOptions.ViewContact: + ContactService.ViewContact(); + break; + case ContactOptions.ViewAllContacts: + ContactService.ViewContacts(); + break; + case ContactOptions.GoBack: + isContactsMenuRunning = false; + break; + } + } + } + + internal static void ViewContact(Contact contact) + { + var panel = new Panel($@"Id: {contact.Id} +First Name: {contact.FirstName} +Last Name: {contact.LastName} +Email Address: {contact.Email} +Phone Number: {contact.PhoneNumber} +Category: {contact.Category.Name}") + { + Header = new PanelHeader("Contact's Info"), + Padding = new Padding(2, 2, 2, 2) + }; + AnsiConsole.Write(panel); + Console.WriteLine("Press anything to continue"); + Console.ReadLine(); + Console.Clear(); + } + + internal static void ViewContacts(List contacts) + { + var table = new Spectre.Console.Table(); + table.AddColumn("Id"); + table.AddColumn("First Name"); + table.AddColumn("Last Name"); + table.AddColumn("Email Address"); + table.AddColumn("Phone Number"); + table.AddColumn("Category"); + foreach (var item in contacts) + { + table.AddRow(item.Id.ToString(), item.FirstName, + item.LastName, item.Email + , item.PhoneNumber, item.Category.Name); + } + AnsiConsole.Write(table); + Console.WriteLine("Press anything to continue"); + Console.ReadLine(); + Console.Clear(); + } + + internal static void ViewCategories(List categories) + { + var table = new Spectre.Console.Table(); + table.AddColumn("Id"); + table.AddColumn("Name"); + foreach (var item in categories) + { + table.AddRow(item.Id.ToString(), item.Name); + } + AnsiConsole.Write(table); + Console.WriteLine("Press anything to continue"); + Console.ReadLine(); + Console.Clear(); + } + + internal static void ViewEmails(List emails) + { + var table = new Table(); + table.AddColumn("Id"); + table.AddColumn("Subject"); + table.AddColumn("Body"); + table.AddColumn("Sent to"); + foreach (var item in emails) + { + table.AddRow(item.Id.ToString(), item.Subject, item.Body, $"{item.Contact.FirstName} {item.Contact.LastName}"); + } + AnsiConsole.Write(table); + Console.WriteLine("Press anything to continue"); + Console.ReadLine(); + Console.Clear(); + } + + internal static void ViewSMSs(List SMSs) + { + var table = new Table(); + table.AddColumn("Id"); + table.AddColumn("Subject"); + table.AddColumn("Sent to"); + foreach (var item in SMSs) + { + table.AddRow(item.Id.ToString(), item.Subject, $"{item.Contact.FirstName} {item.Contact.LastName}"); + } + AnsiConsole.Write(table); + Console.WriteLine("Press anything to continue"); + Console.ReadLine(); + Console.Clear(); + } + } +} diff --git a/PhoneBook/PhoneBook.Ledana/appSettings.json b/PhoneBook/PhoneBook.Ledana/appSettings.json new file mode 100644 index 00000000..26563b83 --- /dev/null +++ b/PhoneBook/PhoneBook.Ledana/appSettings.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "ContactsDb": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ContactsDb;Trust Server Certificate=True;" + } +} \ No newline at end of file diff --git a/PhoneBook/PhoneBookTests.Ledana/InputValidatorTests.cs b/PhoneBook/PhoneBookTests.Ledana/InputValidatorTests.cs new file mode 100644 index 00000000..975c22a5 --- /dev/null +++ b/PhoneBook/PhoneBookTests.Ledana/InputValidatorTests.cs @@ -0,0 +1,81 @@ +using PhoneBook.Ledana; + +namespace TestProject1 +{ + public class InputValidatorTests + { + + [Test] + public void IsEmailValid_WhenCalledWithValidInput_ReturnsTrue() + { + var email = "as@is.it"; + var result = InputValidator.IsEmailValid(email); + + Assert.That(result, Is.True); + } + [Test] + public void IsEmailValid_WithEmailWithoutAtOrDot_ReturnsFalse() + { + var email = "sd@gf"; + var result = InputValidator.IsEmailValid(email); + + Assert.That(result, Is.False); + } + [Test] + public void IsEmailValid_WithEmailWithAtAndWithoutDot_ReturnsFalse() + { + var email = "sd@gf"; + var result = InputValidator.IsEmailValid(email); + + Assert.That(result, Is.False); + } + [Test] + public void IsEmailValid_WithEmailWithDotAndWithoutAt_ReturnsFalse() + { + var email = "sdg.f"; + var result = InputValidator.IsEmailValid(email); + + Assert.That(result, Is.False); + } + [Test] + public void IsNumberValid_WhenCalledWithValidNumber_ReturnsTrue() + { + var number = "+355690124789"; + var result = InputValidator.IsNumberValid(number); + + Assert.That(result, Is.True); + } + [Test] + public void IsNumberValid_WithNumberStartsWithPlusButTooShort_ReturnsTrue() + { + var number = "+35569512"; + var result = InputValidator.IsNumberValid(number); + + Assert.That(result, Is.False); + } + [Test] + public void IsNumberValid_WithNumberDoesntStartsWithPlusAndLongEnough_ReturnsTrue() + { + var number = "0355695127755"; + var result = InputValidator.IsNumberValid(number); + + Assert.That(result, Is.False); + } + [Test] + public void IsNumberValid_WithNumberStartsWithPlusAndLongEnoughButContainsLetters_ReturnsTrue() + { + var number = "+35569op27755"; + var result = InputValidator.IsNumberValid(number); + + Assert.That(result, Is.False); + } + [Test] + public void IsNumberValid_NumberHasOnlyLetters_ReturnsTrue() + { + var number = "+tgrd"; + var result = InputValidator.IsNumberValid(number); + + Assert.That(result, Is.False); + } + } +} diff --git a/PhoneBook/PhoneBookTests.Ledana/PhoneBookTests.Ledana.csproj b/PhoneBook/PhoneBookTests.Ledana/PhoneBookTests.Ledana.csproj new file mode 100644 index 00000000..988051c2 --- /dev/null +++ b/PhoneBook/PhoneBookTests.Ledana/PhoneBookTests.Ledana.csproj @@ -0,0 +1,27 @@ + + + + net10.0 + latest + enable + enable + false + + + + + + + + + + + + + + + + + + + diff --git a/PhoneBook/README.md b/PhoneBook/README.md new file mode 100644 index 00000000..a30b6f92 --- /dev/null +++ b/PhoneBook/README.md @@ -0,0 +1,46 @@ +# PhoneBook +# PhoneBook.Ledana 📖📱 + +## Overview +PhoneBook.Ledana is my first project built with **Entity Framework Core (EF Core)**. +It’s a console-based phone book application that connects to a **SQL Server database**. +The app allows users to manage contacts, send emails and SMS messages, and organize contacts into categories. + +--- + +## Features +- **Contact Management** + - Create contacts with first name, last name, email, phone number, and category (e.g., Family, Friends). + - Phone numbers are **unique** — the app checks for duplicates before saving. + - Input validation ensures emails and phone numbers match the correct format. + +- **Messaging** + - Send **emails** and **SMS messages** to contacts. + - Messages are stored in their own tables (`Emails`, `SMSs`) with a `ContactId` foreign key linking them to the target contact. + +- **Database** + - Built with **EF Core** and SQL Server. + - Tables: `Contacts`, `Categories`, `Emails`, `SMSs`. + - Relationships enforced with foreign keys. +- - **Seeded data**: initial categories and contacts are inserted via `OnModelCreating`. + - **Database lifecycle**: the database is deleted and recreated every time the app runs, ensuring a fresh state for testing and development. + - **Query logging**: every SQL query executed by EF Core is printed to the console for transparency and debugging. + +- **Console UI** + - Uses **Spectre.Console** for rich console output (tables, prompts, etc.). + +- **Testing** + - Unit tests written with **NUnit**. + - Tests cover validation methods (e.g., email and phone number format). + +--- + +## Tech Stack +- **.NET 10.0** +- **Entity Framework Core** +- **SQL Server** +- **Spectre.Console** +- **NUnit** + +--- + From ee510c3434e304abae861584a6df8ba1041f3d23 Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 16:56:19 +0200 Subject: [PATCH 02/10] commented the logging lines in onconfiguring to keep console clean --- PhoneBook/PhoneBook.Ledana/ContactContext.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/ContactContext.cs b/PhoneBook/PhoneBook.Ledana/ContactContext.cs index 89cbd483..bb51c6ce 100644 --- a/PhoneBook/PhoneBook.Ledana/ContactContext.cs +++ b/PhoneBook/PhoneBook.Ledana/ContactContext.cs @@ -23,9 +23,9 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) var connectionString = config.GetConnectionString("ContactsDb"); - optionsBuilder.UseSqlServer(connectionString) - .EnableSensitiveDataLogging() - .UseLoggerFactory(GetLoggerFactory()); + optionsBuilder.UseSqlServer(connectionString); + //.EnableSensitiveDataLogging() + //.UseLoggerFactory(GetLoggerFactory()); } private ILoggerFactory? GetLoggerFactory() { From e5c63ae4c02001f16d94d4ef9e347468bdc19cbd Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:06:04 +0200 Subject: [PATCH 03/10] Added try catch in each method in category controller --- .../Controllers/CategoryController.cs | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs index a2a3d86b..aecdd608 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs @@ -7,31 +7,59 @@ internal class CategoryController { internal static List GetCategories() { - using var context = new ContactContext(); - var categories = context.Categories - .Include(c => c.Contacts) - .ToList(); - return categories; + try + { + using var context = new ContactContext(); + var categories = context.Categories + .Include(c => c.Contacts) + .ToList(); + return categories; + } + catch (Exception e) + { + Console.WriteLine("Couldn't get the categories"); + } } internal static void AddCategory(Category category) { - using var context = new ContactContext(); - context.Categories.Add(category); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Categories.Add(category); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't add the category"); + } } internal static void DeleteCategory(Category category) { - using var context = new ContactContext(); - context.Categories.Remove(category); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Categories.Remove(category); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't delete the category"); + } } internal static void UpdateCategory(Category category) { - using var context = new ContactContext(); - context.Categories.Update(category); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Categories.Update(category); + context.SaveChanges(); + } + cacth (Exception e) + { + Console.WriteLine("Couldn't update the category"); + } } } } From 8e90d2e98cb77aaa1ccfd962945b4455599d98df Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:10:11 +0200 Subject: [PATCH 04/10] Added try catch in each method in contact controller --- .../Controllers/ContactController.cs | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs index a64ab538..6b924206 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs @@ -7,31 +7,59 @@ internal class ContactController { internal static void AddContact(Contact contact) { - using var context = new ContactContext(); - context.Contacts.Add(contact); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Contacts.Add(contact); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't add the contact"); + } } internal static void DeleteContact(Contact contact) { - using var context = new ContactContext(); - context.Contacts.Remove(contact); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Contacts.Remove(contact); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't delete the contact"); + } } internal static List GetAllContacts() { - using var context = new ContactContext(); - var contacts = context.Contacts.Include(c => c.Category) - .ToList(); - return contacts; + try + { + using var context = new ContactContext(); + var contacts = context.Contacts.Include(c => c.Category) + .ToList(); + return contacts; + } + catch (Exception e) + { + Console.WriteLine("Couldn't get contacts"); + } } internal static void UpdateContact(Contact contact) { - using var context = new ContactContext(); - context.Contacts.Update(contact); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Contacts.Update(contact); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't update the contact"); + } } internal static bool ValidatePhoneNumber(string phoneNumber) { From 542ff768251b45fdf8a8973c1a81ad3a2fcfca64 Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:13:31 +0200 Subject: [PATCH 05/10] Added try catch in each method in email controller --- .../Controllers/EmailController.cs | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs index c09b77d8..468d716b 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs @@ -7,17 +7,31 @@ internal class EmailController { internal static void SendEmail(Email email) { - using var context = new ContactContext(); - context.Emails.Add(email); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.Emails.Add(email); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't send email"); + } } internal static List GetEmails() { - using var context = new ContactContext(); - var emails = context.Emails - .Include(e => e.Contact) - .ToList(); - return emails; + try + { + using var context = new ContactContext(); + var emails = context.Emails + .Include(e => e.Contact) + .ToList(); + return emails; + } + catch + { + Console.WriteLine("Couldn't get emails"); + } } } } From 440a2d3c9abde8832c113f81bdd741d0f0b8f1cd Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:15:21 +0200 Subject: [PATCH 06/10] Added try catch in each method in SMS controller --- .../Controllers/SMSController.cs | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs index 601425e8..00ae975c 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs @@ -7,18 +7,32 @@ internal class SMSController { internal static List GetSMS() { - using var context = new ContactContext(); - var SMSs = context.SMSs - .Include(s => s.Contact) - .ToList(); - return SMSs; + try + { + using var context = new ContactContext(); + var SMSs = context.SMSs + .Include(s => s.Contact) + .ToList(); + return SMSs; + } + catch (Exception e) + { + Console.WriteLine("Couldn't get SMSs"); + } } internal static void SendSMS(SMS sms) { - using var context = new ContactContext(); - context.SMSs.Add(sms); - context.SaveChanges(); + try + { + using var context = new ContactContext(); + context.SMSs.Add(sms); + context.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Couldn't send SMS"); + } } } } From 258844c2107004d029706bc435d73ce8c878fe52 Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:24:10 +0200 Subject: [PATCH 07/10] Added lanchsettings.json in gitignore file --- PhoneBook/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PhoneBook/.gitignore b/PhoneBook/.gitignore index 9491a2fd..2ef6f4ab 100644 --- a/PhoneBook/.gitignore +++ b/PhoneBook/.gitignore @@ -10,6 +10,9 @@ *.userosscache *.sln.docstates +# Local environment settings +launchSettings.json + # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs From 7151768114a400bfe28b5d10eae2cddfe959a9db Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:33:09 +0200 Subject: [PATCH 08/10] Added block-scoped namespace instead of file-scoped in every class --- PhoneBook/PhoneBook.Ledana/ContactContext.cs | 6 +----- .../PhoneBook.Ledana/Controllers/CategoryController.cs | 7 +++---- .../PhoneBook.Ledana/Controllers/ContactController.cs | 5 ++--- PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs | 5 ++--- PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs | 5 ++--- PhoneBook/PhoneBook.Ledana/Enums.cs | 4 +--- PhoneBook/PhoneBook.Ledana/InputValidator.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Models/Category.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Models/Contact.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Models/Email.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Models/SMS.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Services/ContactService.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Services/EmailService.cs | 4 +--- PhoneBook/PhoneBook.Ledana/Services/SMSService.cs | 4 +--- PhoneBook/PhoneBook.Ledana/UserInterface.cs | 4 +--- 16 files changed, 21 insertions(+), 51 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/ContactContext.cs b/PhoneBook/PhoneBook.Ledana/ContactContext.cs index bb51c6ce..145a9e80 100644 --- a/PhoneBook/PhoneBook.Ledana/ContactContext.cs +++ b/PhoneBook/PhoneBook.Ledana/ContactContext.cs @@ -3,8 +3,7 @@ using Microsoft.Extensions.Logging; using PhoneBook.Ledana.Models; -namespace PhoneBook.Ledana -{ +namespace PhoneBook.Ledana; internal class ContactContext : DbContext { public DbSet Contacts { get; set; } @@ -162,6 +161,3 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); } } - - -} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs index aecdd608..c7372706 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/CategoryController.cs @@ -1,8 +1,7 @@ using Microsoft.EntityFrameworkCore; using PhoneBook.Ledana.Models; -namespace PhoneBook.Ledana.Controllers -{ +namespace PhoneBook.Ledana.Controllers; internal class CategoryController { internal static List GetCategories() @@ -18,6 +17,7 @@ internal static List GetCategories() catch (Exception e) { Console.WriteLine("Couldn't get the categories"); + return []; } } internal static void AddCategory(Category category) @@ -56,10 +56,9 @@ internal static void UpdateCategory(Category category) context.Categories.Update(category); context.SaveChanges(); } - cacth (Exception e) + catch (Exception e) { Console.WriteLine("Couldn't update the category"); } } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs index 6b924206..cb095427 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs @@ -1,8 +1,7 @@ using Microsoft.EntityFrameworkCore; using PhoneBook.Ledana.Models; -namespace PhoneBook.Ledana.Controllers -{ +namespace PhoneBook.Ledana.Controllers; internal class ContactController { internal static void AddContact(Contact contact) @@ -45,6 +44,7 @@ internal static List GetAllContacts() catch (Exception e) { Console.WriteLine("Couldn't get contacts"); + return []; } } @@ -68,4 +68,3 @@ internal static bool ValidatePhoneNumber(string phoneNumber) return phoneNumberExists > 0; } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs index 468d716b..8b3712a8 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/EmailController.cs @@ -1,8 +1,7 @@ using Microsoft.EntityFrameworkCore; using PhoneBook.Ledana.Models; -namespace PhoneBook.Ledana.Controllers -{ +namespace PhoneBook.Ledana.Controllers; internal class EmailController { internal static void SendEmail(Email email) @@ -31,7 +30,7 @@ internal static List GetEmails() catch { Console.WriteLine("Couldn't get emails"); + return []; } } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs index 00ae975c..2031843a 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/SMSController.cs @@ -1,8 +1,7 @@ using Microsoft.EntityFrameworkCore; using PhoneBook.Ledana.Models; -namespace PhoneBook.Ledana.Controllers -{ +namespace PhoneBook.Ledana.Controllers; internal class SMSController { internal static List GetSMS() @@ -18,6 +17,7 @@ internal static List GetSMS() catch (Exception e) { Console.WriteLine("Couldn't get SMSs"); + return []; } } @@ -35,4 +35,3 @@ internal static void SendSMS(SMS sms) } } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Enums.cs b/PhoneBook/PhoneBook.Ledana/Enums.cs index cb8dd89c..9d6b2b4a 100644 --- a/PhoneBook/PhoneBook.Ledana/Enums.cs +++ b/PhoneBook/PhoneBook.Ledana/Enums.cs @@ -2,8 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace PhoneBook.Ledana -{ +namespace PhoneBook.Ledana; internal class Enums { internal enum MenuOptions @@ -44,4 +43,3 @@ internal enum SMSOptions GoBack } } -} diff --git a/PhoneBook/PhoneBook.Ledana/InputValidator.cs b/PhoneBook/PhoneBook.Ledana/InputValidator.cs index 6525ad8c..8aa5b93a 100644 --- a/PhoneBook/PhoneBook.Ledana/InputValidator.cs +++ b/PhoneBook/PhoneBook.Ledana/InputValidator.cs @@ -2,8 +2,7 @@ using Spectre.Console; using System.Text.RegularExpressions; -namespace PhoneBook.Ledana -{ +namespace PhoneBook.Ledana; public static class InputValidator { public static string ValidateEmail() @@ -41,4 +40,3 @@ public static bool IsNumberValid(string phoneNumber) //&& !ContactController.ValidatePhoneNumber(phoneNumber); } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Models/Category.cs b/PhoneBook/PhoneBook.Ledana/Models/Category.cs index b288f0e7..2cc4408f 100644 --- a/PhoneBook/PhoneBook.Ledana/Models/Category.cs +++ b/PhoneBook/PhoneBook.Ledana/Models/Category.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace PhoneBook.Ledana.Models -{ +namespace PhoneBook.Ledana.Models; internal class Category { public int Id { get; set; } public string Name { get; set; } = null!; public List Contacts { get; set; } = []; } -} diff --git a/PhoneBook/PhoneBook.Ledana/Models/Contact.cs b/PhoneBook/PhoneBook.Ledana/Models/Contact.cs index 8ca028a8..d83bbbd7 100644 --- a/PhoneBook/PhoneBook.Ledana/Models/Contact.cs +++ b/PhoneBook/PhoneBook.Ledana/Models/Contact.cs @@ -3,8 +3,7 @@ using System.Collections.Generic; using System.Text; -namespace PhoneBook.Ledana.Models -{ +namespace PhoneBook.Ledana.Models; [Index(nameof(PhoneNumber), IsUnique = true)] internal class Contact { @@ -18,4 +17,3 @@ internal class Contact public List Emails { get; set; } = []; public List SMSs { get; set; } = []; } -} diff --git a/PhoneBook/PhoneBook.Ledana/Models/Email.cs b/PhoneBook/PhoneBook.Ledana/Models/Email.cs index 7f07f621..01f0d676 100644 --- a/PhoneBook/PhoneBook.Ledana/Models/Email.cs +++ b/PhoneBook/PhoneBook.Ledana/Models/Email.cs @@ -2,8 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace PhoneBook.Ledana.Models -{ +namespace PhoneBook.Ledana.Models; internal class Email { public int Id { get; set; } @@ -12,4 +11,3 @@ internal class Email public int ContactId { get; set; } public Contact? Contact { get; set; } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Models/SMS.cs b/PhoneBook/PhoneBook.Ledana/Models/SMS.cs index 76854e10..5aadbf8d 100644 --- a/PhoneBook/PhoneBook.Ledana/Models/SMS.cs +++ b/PhoneBook/PhoneBook.Ledana/Models/SMS.cs @@ -2,8 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace PhoneBook.Ledana.Models -{ +namespace PhoneBook.Ledana.Models; internal class SMS { public int Id { get; set; } @@ -11,4 +10,3 @@ internal class SMS public int ContactId { get; set; } public Contact? Contact { get; set; } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs b/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs index e295df79..4669a78b 100644 --- a/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs +++ b/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs @@ -2,8 +2,7 @@ using PhoneBook.Ledana.Models; using Spectre.Console; -namespace PhoneBook.Ledana.Services -{ +namespace PhoneBook.Ledana.Services; internal class CategoryServices { internal static void AddCategory() @@ -63,4 +62,3 @@ internal static void ViewCategories() UserInterface.ViewCategories(categories); } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs b/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs index 37551029..b0d21e9f 100644 --- a/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs +++ b/PhoneBook/PhoneBook.Ledana/Services/ContactService.cs @@ -2,8 +2,7 @@ using PhoneBook.Ledana.Models; using Spectre.Console; -namespace PhoneBook.Ledana.Services -{ +namespace PhoneBook.Ledana.Services; internal class ContactService { internal static void AddContact() @@ -89,4 +88,3 @@ internal static void ViewContacts() return contact; } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs b/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs index b3363a42..2c70b70e 100644 --- a/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs +++ b/PhoneBook/PhoneBook.Ledana/Services/EmailService.cs @@ -2,8 +2,7 @@ using PhoneBook.Ledana.Models; using Spectre.Console; -namespace PhoneBook.Ledana.Services -{ +namespace PhoneBook.Ledana.Services; internal class EmailService { internal static void SendEmail() @@ -28,4 +27,3 @@ internal static void ViewEmails() UserInterface.ViewEmails(emails); } } -} diff --git a/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs b/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs index f225bdad..0c46b416 100644 --- a/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs +++ b/PhoneBook/PhoneBook.Ledana/Services/SMSService.cs @@ -2,8 +2,7 @@ using PhoneBook.Ledana.Models; using Spectre.Console; -namespace PhoneBook.Ledana.Services -{ +namespace PhoneBook.Ledana.Services; internal class SMSService { internal static void SendSMS() @@ -28,4 +27,3 @@ internal static void ViewSMSs() UserInterface.ViewSMSs(SMSs); } } -} diff --git a/PhoneBook/PhoneBook.Ledana/UserInterface.cs b/PhoneBook/PhoneBook.Ledana/UserInterface.cs index a051996a..dd4ffb97 100644 --- a/PhoneBook/PhoneBook.Ledana/UserInterface.cs +++ b/PhoneBook/PhoneBook.Ledana/UserInterface.cs @@ -3,8 +3,7 @@ using Spectre.Console; using static PhoneBook.Ledana.Enums; -namespace PhoneBook.Ledana -{ +namespace PhoneBook.Ledana; internal class UserInterface { internal static void MainMenu() @@ -267,4 +266,3 @@ internal static void ViewSMSs(List SMSs) Console.Clear(); } } -} From e04d8d4eb1843b40a148fc3ca28f16dae329fb7a Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:35:11 +0200 Subject: [PATCH 09/10] Changed .Count() to .Any() in validatenumber method in contact controller --- PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs index cb095427..4ce4600a 100644 --- a/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs +++ b/PhoneBook/PhoneBook.Ledana/Controllers/ContactController.cs @@ -64,7 +64,7 @@ internal static void UpdateContact(Contact contact) internal static bool ValidatePhoneNumber(string phoneNumber) { using var context = new ContactContext(); - var phoneNumberExists = context.Contacts.Where(c => c.PhoneNumber == phoneNumber).Count(); - return phoneNumberExists > 0; + var phoneNumberExists = context.Contacts.Where(c => c.PhoneNumber == phoneNumber).Any(); + return phoneNumberExists; } } From 481475fd042c90912f1cb48de040fa99840a458a Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 17:43:08 +0200 Subject: [PATCH 10/10] made the getcategoryoptioninput method return category? instead of category --- PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs b/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs index 4669a78b..7a84724d 100644 --- a/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs +++ b/PhoneBook/PhoneBook.Ledana/Services/CategoryServices.cs @@ -25,7 +25,7 @@ internal static void DeleteCategory() CategoryController.DeleteCategory(category); } - internal static Category GetCategoryOptionInput() + internal static Category? GetCategoryOptionInput() { List categories = CategoryController.GetCategories(); if (categories.Count == 0)