Yuyuqt commited on
Commit
c596926
·
1 Parent(s): 907ba54

feat: authorization

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Database/Database.csproj +22 -0
  2. Database/Models/Book.cs +31 -0
  3. Database/Models/Borrowing.cs +29 -0
  4. Database/Models/Category.cs +13 -0
  5. Database/Models/LibraryManagementContext.cs +175 -0
  6. Database/Models/Membership.cs +21 -0
  7. Database/Models/User.cs +39 -0
  8. Database/Models/UserSubscription.cs +23 -0
  9. Database/Models/Wishlist.cs +17 -0
  10. LibraryManagement.Backend/Features/Auth/AuthController.cs +44 -0
  11. LibraryManagement.Backend/Features/Auth/AuthModels.cs +26 -0
  12. LibraryManagement.Backend/Features/Auth/AuthService.cs +101 -0
  13. LibraryManagement.Backend/Features/Users/UserController.cs +23 -0
  14. LibraryManagement.Backend/Features/Users/UserService.cs +30 -0
  15. LibraryManagement.Backend/LibraryManagement.Backend.csproj +20 -0
  16. LibraryManagement.Backend/LibraryManagement.Backend.http +6 -0
  17. LibraryManagement.Backend/Program.cs +83 -0
  18. {LibraryManagement → LibraryManagement.Backend}/Properties/launchSettings.json +7 -4
  19. LibraryManagement.Backend/WeatherForecast.cs +13 -0
  20. {LibraryManagement → LibraryManagement.Backend}/appsettings.Development.json +0 -0
  21. LibraryManagement.Backend/appsettings.json +17 -0
  22. LibraryManagement.Frontend/Components/App.razor +20 -0
  23. LibraryManagement.Frontend/Components/Layout/MainLayout.razor +23 -0
  24. LibraryManagement.Frontend/Components/Layout/MainLayout.razor.css +96 -0
  25. LibraryManagement.Frontend/Components/Layout/NavMenu.razor +30 -0
  26. LibraryManagement.Frontend/Components/Layout/NavMenu.razor.css +105 -0
  27. LibraryManagement.Frontend/Components/Pages/Counter.razor +19 -0
  28. LibraryManagement/Views/Shared/Error.cshtml → LibraryManagement.Frontend/Components/Pages/Error.razor +17 -6
  29. LibraryManagement.Frontend/Components/Pages/Home.razor +7 -0
  30. LibraryManagement.Frontend/Components/Pages/Weather.razor +64 -0
  31. LibraryManagement.Frontend/Components/Routes.razor +6 -0
  32. LibraryManagement.Frontend/Components/_Imports.razor +10 -0
  33. LibraryManagement/LibraryManagement.csproj → LibraryManagement.Frontend/LibraryManagement.Frontend.csproj +0 -0
  34. {LibraryManagement → LibraryManagement.Frontend}/Program.cs +9 -9
  35. LibraryManagement.Frontend/Properties/launchSettings.json +38 -0
  36. LibraryManagement.Frontend/appsettings.Development.json +8 -0
  37. {LibraryManagement → LibraryManagement.Frontend}/appsettings.json +0 -0
  38. LibraryManagement.Frontend/wwwroot/app.css +51 -0
  39. {LibraryManagement/wwwroot/lib/bootstrap/dist/css → LibraryManagement.Frontend/wwwroot/bootstrap}/bootstrap.min.css +0 -0
  40. {LibraryManagement/wwwroot/lib/bootstrap/dist/css → LibraryManagement.Frontend/wwwroot/bootstrap}/bootstrap.min.css.map +0 -0
  41. LibraryManagement.Frontend/wwwroot/favicon.png +0 -0
  42. LibraryManagement.slnx +3 -1
  43. LibraryManagement/Controllers/HomeController.cs +0 -32
  44. LibraryManagement/Models/ErrorViewModel.cs +0 -9
  45. LibraryManagement/Views/Home/Index.cshtml +0 -8
  46. LibraryManagement/Views/Home/Privacy.cshtml +0 -6
  47. LibraryManagement/Views/Shared/_Layout.cshtml +0 -49
  48. LibraryManagement/Views/Shared/_Layout.cshtml.css +0 -48
  49. LibraryManagement/Views/Shared/_ValidationScriptsPartial.cshtml +0 -2
  50. LibraryManagement/Views/_ViewImports.cshtml +0 -3
Database/Database.csproj ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <PropertyGroup>
4
+ <TargetFramework>net8.0</TargetFramework>
5
+ <ImplicitUsings>enable</ImplicitUsings>
6
+ <Nullable>enable</Nullable>
7
+ </PropertyGroup>
8
+
9
+ <ItemGroup>
10
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
11
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
12
+ <PrivateAssets>all</PrivateAssets>
13
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
14
+ </PackageReference>
15
+ <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
16
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
17
+ <PrivateAssets>all</PrivateAssets>
18
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
19
+ </PackageReference>
20
+ </ItemGroup>
21
+
22
+ </Project>
Database/Models/Book.cs ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class Book
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public string Title { get; set; } = null!;
11
+
12
+ public string Isbn { get; set; } = null!;
13
+
14
+ public string Author { get; set; } = null!;
15
+
16
+ public string Status { get; set; } = null!;
17
+
18
+ public bool IsActive { get; set; }
19
+
20
+ public DateTime CreatedAt { get; set; }
21
+
22
+ public string? Description { get; set; }
23
+
24
+ public string? CoverUrl { get; set; }
25
+
26
+ public virtual ICollection<Borrowing> Borrowings { get; set; } = new List<Borrowing>();
27
+
28
+ public virtual ICollection<Wishlist> Wishlists { get; set; } = new List<Wishlist>();
29
+
30
+ public virtual ICollection<Category> Categories { get; set; } = new List<Category>();
31
+ }
Database/Models/Borrowing.cs ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class Borrowing
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public int UserId { get; set; }
11
+
12
+ public int BookId { get; set; }
13
+
14
+ public DateTime BorrowDate { get; set; }
15
+
16
+ public DateTime DueDate { get; set; }
17
+
18
+ public DateTime? ReturnDate { get; set; }
19
+
20
+ public string Status { get; set; } = null!;
21
+
22
+ public decimal FineAmount { get; set; }
23
+
24
+ public bool IsFinePaid { get; set; }
25
+
26
+ public virtual Book Book { get; set; } = null!;
27
+
28
+ public virtual User User { get; set; } = null!;
29
+ }
Database/Models/Category.cs ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class Category
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public string Name { get; set; } = null!;
11
+
12
+ public virtual ICollection<Book> Books { get; set; } = new List<Book>();
13
+ }
Database/Models/LibraryManagementContext.cs ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using Microsoft.EntityFrameworkCore;
4
+
5
+ namespace Database.Models;
6
+
7
+ public partial class LibraryManagementContext : DbContext
8
+ {
9
+ public LibraryManagementContext()
10
+ {
11
+ }
12
+
13
+ public LibraryManagementContext(DbContextOptions<LibraryManagementContext> options)
14
+ : base(options)
15
+ {
16
+ }
17
+
18
+ public virtual DbSet<Book> Books { get; set; }
19
+
20
+ public virtual DbSet<Borrowing> Borrowings { get; set; }
21
+
22
+ public virtual DbSet<Category> Categories { get; set; }
23
+
24
+ public virtual DbSet<Membership> Memberships { get; set; }
25
+
26
+ public virtual DbSet<User> Users { get; set; }
27
+
28
+ public virtual DbSet<UserSubscription> UserSubscriptions { get; set; }
29
+
30
+ public virtual DbSet<Wishlist> Wishlists { get; set; }
31
+
32
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
33
+ #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
34
+ => optionsBuilder.UseSqlServer("Server=DESKTOP-BP9A061;Database=LibraryManagement;User Id=sa;Password=sasa@123;TrustServerCertificate=True;");
35
+
36
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
37
+ {
38
+ modelBuilder.Entity<Book>(entity =>
39
+ {
40
+ entity.HasKey(e => e.Id).HasName("PK__Books__3214EC07AE1974C8");
41
+
42
+ entity.HasIndex(e => e.Isbn, "UQ__Books__447D36EA79CF66CE").IsUnique();
43
+
44
+ entity.Property(e => e.Author).HasMaxLength(100);
45
+ entity.Property(e => e.CreatedAt)
46
+ .HasDefaultValueSql("(getdate())")
47
+ .HasColumnType("datetime");
48
+ entity.Property(e => e.IsActive).HasDefaultValue(true);
49
+ entity.Property(e => e.Isbn)
50
+ .HasMaxLength(20)
51
+ .HasColumnName("ISBN");
52
+ entity.Property(e => e.Status)
53
+ .HasMaxLength(20)
54
+ .HasDefaultValue("Available");
55
+ entity.Property(e => e.Title).HasMaxLength(200);
56
+
57
+ entity.HasMany(d => d.Categories).WithMany(p => p.Books)
58
+ .UsingEntity<Dictionary<string, object>>(
59
+ "BookCategory",
60
+ r => r.HasOne<Category>().WithMany()
61
+ .HasForeignKey("CategoryId")
62
+ .HasConstraintName("FK_BookCategories_Categories"),
63
+ l => l.HasOne<Book>().WithMany()
64
+ .HasForeignKey("BookId")
65
+ .HasConstraintName("FK_BookCategories_Books"),
66
+ j =>
67
+ {
68
+ j.HasKey("BookId", "CategoryId").HasName("PK__BookCate__9C7051A74E7D221D");
69
+ j.ToTable("BookCategories");
70
+ });
71
+ });
72
+
73
+ modelBuilder.Entity<Borrowing>(entity =>
74
+ {
75
+ entity.HasKey(e => e.Id).HasName("PK__Borrowin__3214EC07EA26D8CD");
76
+
77
+ entity.Property(e => e.BorrowDate)
78
+ .HasDefaultValueSql("(getdate())")
79
+ .HasColumnType("datetime");
80
+ entity.Property(e => e.DueDate).HasColumnType("datetime");
81
+ entity.Property(e => e.FineAmount).HasColumnType("decimal(10, 2)");
82
+ entity.Property(e => e.ReturnDate).HasColumnType("datetime");
83
+ entity.Property(e => e.Status)
84
+ .HasMaxLength(20)
85
+ .HasDefaultValue("Active");
86
+
87
+ entity.HasOne(d => d.Book).WithMany(p => p.Borrowings)
88
+ .HasForeignKey(d => d.BookId)
89
+ .OnDelete(DeleteBehavior.ClientSetNull)
90
+ .HasConstraintName("FK_Borrowings_Books");
91
+
92
+ entity.HasOne(d => d.User).WithMany(p => p.Borrowings)
93
+ .HasForeignKey(d => d.UserId)
94
+ .OnDelete(DeleteBehavior.ClientSetNull)
95
+ .HasConstraintName("FK_Borrowings_Users");
96
+ });
97
+
98
+ modelBuilder.Entity<Category>(entity =>
99
+ {
100
+ entity.HasKey(e => e.Id).HasName("PK__Categori__3214EC0751B5797D");
101
+
102
+ entity.HasIndex(e => e.Name, "UQ__Categori__737584F622B16D3A").IsUnique();
103
+
104
+ entity.Property(e => e.Name).HasMaxLength(100);
105
+ });
106
+
107
+ modelBuilder.Entity<Membership>(entity =>
108
+ {
109
+ entity.HasKey(e => e.Id).HasName("PK__Membersh__3214EC07A6F5A55F");
110
+
111
+ entity.HasIndex(e => e.Type, "IX_Memberships_Type").IsUnique();
112
+
113
+ entity.Property(e => e.Price).HasColumnType("decimal(10, 2)");
114
+ entity.Property(e => e.Type).HasMaxLength(50);
115
+ });
116
+
117
+ modelBuilder.Entity<User>(entity =>
118
+ {
119
+ entity.HasKey(e => e.Id).HasName("PK__Users__3214EC0771D7BED2");
120
+
121
+ entity.HasIndex(e => e.Email, "UQ__Users__A9D10534F91FFF73").IsUnique();
122
+
123
+ entity.Property(e => e.Address).HasMaxLength(255);
124
+ entity.Property(e => e.CreatedAt)
125
+ .HasDefaultValueSql("(getdate())")
126
+ .HasColumnType("datetime");
127
+ entity.Property(e => e.Email).HasMaxLength(100);
128
+ entity.Property(e => e.FullName).HasMaxLength(100);
129
+ entity.Property(e => e.IsActive).HasDefaultValue(true);
130
+ entity.Property(e => e.PhoneNumber).HasMaxLength(20);
131
+ entity.Property(e => e.Role)
132
+ .HasMaxLength(20)
133
+ .HasDefaultValue("User");
134
+ entity.Property(e => e.StudentId).HasMaxLength(20);
135
+ entity.Property(e => e.SuspensionEndDate).HasColumnType("datetime");
136
+ entity.Property(e => e.UpdatedAt).HasColumnType("datetime");
137
+ });
138
+
139
+ modelBuilder.Entity<UserSubscription>(entity =>
140
+ {
141
+ entity.HasKey(e => e.Id).HasName("PK__UserSubs__3214EC07E3FBC0EC");
142
+
143
+ entity.Property(e => e.ExpiryDate).HasColumnType("datetime");
144
+ entity.Property(e => e.IsActive).HasDefaultValue(true);
145
+ entity.Property(e => e.StartDate).HasColumnType("datetime");
146
+
147
+ entity.HasOne(d => d.Membership).WithMany(p => p.UserSubscriptions)
148
+ .HasForeignKey(d => d.MembershipId)
149
+ .OnDelete(DeleteBehavior.ClientSetNull)
150
+ .HasConstraintName("FK_UserSubscriptions_Memberships");
151
+
152
+ entity.HasOne(d => d.User).WithMany(p => p.UserSubscriptions)
153
+ .HasForeignKey(d => d.UserId)
154
+ .OnDelete(DeleteBehavior.ClientSetNull)
155
+ .HasConstraintName("FK_UserSubscriptions_Users");
156
+ });
157
+
158
+ modelBuilder.Entity<Wishlist>(entity =>
159
+ {
160
+ entity.HasKey(e => e.Id).HasName("PK__Wishlist__3214EC07F63D8F81");
161
+
162
+ entity.HasOne(d => d.Book).WithMany(p => p.Wishlists)
163
+ .HasForeignKey(d => d.BookId)
164
+ .HasConstraintName("FK_Wishlists_Books");
165
+
166
+ entity.HasOne(d => d.User).WithMany(p => p.Wishlists)
167
+ .HasForeignKey(d => d.UserId)
168
+ .HasConstraintName("FK_Wishlists_Users");
169
+ });
170
+
171
+ OnModelCreatingPartial(modelBuilder);
172
+ }
173
+
174
+ partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
175
+ }
Database/Models/Membership.cs ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class Membership
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public string Type { get; set; } = null!;
11
+
12
+ public int MaxBooks { get; set; }
13
+
14
+ public int BorrowingDays { get; set; }
15
+
16
+ public decimal Price { get; set; }
17
+
18
+ public int DurationMonths { get; set; }
19
+
20
+ public virtual ICollection<UserSubscription> UserSubscriptions { get; set; } = new List<UserSubscription>();
21
+ }
Database/Models/User.cs ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class User
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public string FullName { get; set; } = null!;
11
+
12
+ public string Email { get; set; } = null!;
13
+
14
+ public string PasswordHash { get; set; } = null!;
15
+
16
+ public string? PhoneNumber { get; set; }
17
+
18
+ public string Role { get; set; } = null!;
19
+
20
+ public bool IsActive { get; set; }
21
+
22
+ public DateTime CreatedAt { get; set; }
23
+
24
+ public DateTime? UpdatedAt { get; set; }
25
+
26
+ public string? StudentId { get; set; }
27
+
28
+ public bool? BanStatus { get; set; }
29
+
30
+ public DateTime? SuspensionEndDate { get; set; }
31
+
32
+ public string? Address { get; set; }
33
+
34
+ public virtual ICollection<Borrowing> Borrowings { get; set; } = new List<Borrowing>();
35
+
36
+ public virtual ICollection<UserSubscription> UserSubscriptions { get; set; } = new List<UserSubscription>();
37
+
38
+ public virtual ICollection<Wishlist> Wishlists { get; set; } = new List<Wishlist>();
39
+ }
Database/Models/UserSubscription.cs ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class UserSubscription
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public int UserId { get; set; }
11
+
12
+ public int MembershipId { get; set; }
13
+
14
+ public DateTime StartDate { get; set; }
15
+
16
+ public DateTime ExpiryDate { get; set; }
17
+
18
+ public bool IsActive { get; set; }
19
+
20
+ public virtual Membership Membership { get; set; } = null!;
21
+
22
+ public virtual User User { get; set; } = null!;
23
+ }
Database/Models/Wishlist.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace Database.Models;
5
+
6
+ public partial class Wishlist
7
+ {
8
+ public int Id { get; set; }
9
+
10
+ public int UserId { get; set; }
11
+
12
+ public int BookId { get; set; }
13
+
14
+ public virtual Book Book { get; set; } = null!;
15
+
16
+ public virtual User User { get; set; } = null!;
17
+ }
LibraryManagement.Backend/Features/Auth/AuthController.cs ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Microsoft.AspNetCore.Mvc;
2
+
3
+ namespace LibraryManagement.Backend.Features.Auth
4
+ {
5
+ [ApiController]
6
+ [Route("api/auth")]
7
+ public class AuthController : ControllerBase
8
+ {
9
+ private readonly IAuthService _authService;
10
+
11
+ public AuthController(IAuthService authService)
12
+ {
13
+ _authService = authService;
14
+ }
15
+
16
+ [HttpPost("register")]
17
+ public async Task<ActionResult<AuthResponse>> Register([FromBody] RegisterRequest request)
18
+ {
19
+ try
20
+ {
21
+ var response = await _authService.Register(request);
22
+ return Ok(response);
23
+ }
24
+ catch (Exception ex)
25
+ {
26
+ return BadRequest(new { message = ex.Message });
27
+ }
28
+ }
29
+
30
+ [HttpPost("login")]
31
+ public async Task<ActionResult<AuthResponse>> Login([FromBody] LoginRequest request)
32
+ {
33
+ try
34
+ {
35
+ var response = await _authService.Login(request);
36
+ return Ok(response);
37
+ }
38
+ catch (Exception ex)
39
+ {
40
+ return Unauthorized(new { message = ex.Message });
41
+ }
42
+ }
43
+ }
44
+ }
LibraryManagement.Backend/Features/Auth/AuthModels.cs ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace LibraryManagement.Backend.Features.Auth
2
+ {
3
+ public class RegisterRequest
4
+ {
5
+ public string FullName { get; set; } = string.Empty;
6
+ public string Email { get; set; } = string.Empty;
7
+ public string Password { get; set; } = string.Empty;
8
+ public string? PhoneNumber { get; set; }
9
+ public string? Address { get; set; }
10
+ public string? StudentId { get; set; }
11
+ }
12
+
13
+ public class LoginRequest
14
+ {
15
+ public string Email { get; set; } = string.Empty;
16
+ public string Password { get; set; } = string.Empty;
17
+ }
18
+
19
+ public class AuthResponse
20
+ {
21
+ public string Token { get; set; } = string.Empty;
22
+ public string FullName { get; set; } = string.Empty;
23
+ public string Role { get; set; } = string.Empty;
24
+ public DateTime Expiry { get; set; }
25
+ }
26
+ }
LibraryManagement.Backend/Features/Auth/AuthService.cs ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Database.Models;
2
+ using Microsoft.EntityFrameworkCore;
3
+ using Microsoft.IdentityModel.Tokens;
4
+ using System.IdentityModel.Tokens.Jwt;
5
+ using System.Security.Claims;
6
+ using System.Text;
7
+
8
+ namespace LibraryManagement.Backend.Features.Auth
9
+ {
10
+ public interface IAuthService
11
+ {
12
+ Task<AuthResponse> Register(RegisterRequest request);
13
+ Task<AuthResponse> Login(LoginRequest request);
14
+ }
15
+
16
+ public class AuthService : IAuthService
17
+ {
18
+ private readonly LibraryManagementContext _context;
19
+ private readonly IConfiguration _configuration;
20
+
21
+ public AuthService(LibraryManagementContext context, IConfiguration configuration)
22
+ {
23
+ _context = context;
24
+ _configuration = configuration;
25
+ }
26
+
27
+ public async Task<AuthResponse> Register(RegisterRequest request)
28
+ {
29
+ if (await _context.Users.AnyAsync(u => u.Email == request.Email))
30
+ {
31
+ throw new Exception("User already exists with this email.");
32
+ }
33
+
34
+ var user = new User
35
+ {
36
+ FullName = request.FullName,
37
+ Email = request.Email,
38
+ PhoneNumber = request.PhoneNumber,
39
+ Address = request.Address,
40
+ StudentId = request.StudentId,
41
+ PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password),
42
+ Role = "Member", // Default role
43
+ IsActive = true,
44
+ CreatedAt = DateTime.UtcNow
45
+ };
46
+
47
+ _context.Users.Add(user);
48
+ await _context.SaveChangesAsync();
49
+
50
+ return await AuthenticateUser(user);
51
+ }
52
+
53
+ public async Task<AuthResponse> Login(LoginRequest request)
54
+ {
55
+ var user = await _context.Users.FirstOrDefaultAsync(u => u.Email == request.Email);
56
+
57
+ if (user == null || !BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash))
58
+ {
59
+ throw new Exception("Invalid email or password.");
60
+ }
61
+
62
+ if (!user.IsActive)
63
+ {
64
+ throw new Exception("User account is deactivated.");
65
+ }
66
+
67
+ return await AuthenticateUser(user);
68
+ }
69
+
70
+ private async Task<AuthResponse> AuthenticateUser(User user)
71
+ {
72
+ var tokenHandler = new JwtSecurityTokenHandler();
73
+ var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Secret"] ?? "YourSuperSecretKeyForLibraryManagementSystem_AtLeast32CharsLong");
74
+
75
+ var tokenDescriptor = new SecurityTokenDescriptor
76
+ {
77
+ Subject = new ClaimsIdentity(new[]
78
+ {
79
+ new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
80
+ new Claim(ClaimTypes.Email, user.Email),
81
+ new Claim(ClaimTypes.Name, user.FullName),
82
+ new Claim(ClaimTypes.Role, user.Role)
83
+ }),
84
+ Expires = DateTime.UtcNow.AddDays(7),
85
+ SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
86
+ Issuer = _configuration["Jwt:Issuer"],
87
+ Audience = _configuration["Jwt:Audience"]
88
+ };
89
+
90
+ var token = tokenHandler.CreateToken(tokenDescriptor);
91
+
92
+ return new AuthResponse
93
+ {
94
+ Token = tokenHandler.WriteToken(token),
95
+ FullName = user.FullName,
96
+ Role = user.Role,
97
+ Expiry = tokenDescriptor.Expires.Value
98
+ };
99
+ }
100
+ }
101
+ }
LibraryManagement.Backend/Features/Users/UserController.cs ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Microsoft.AspNetCore.Mvc;
2
+
3
+ namespace LibraryManagement.Backend.Features.Users
4
+ {
5
+ [ApiController]
6
+ [Route("api/users")]
7
+ public class UserController : ControllerBase
8
+ {
9
+ private readonly IUserService _userService;
10
+
11
+ public UserController(IUserService userService)
12
+ {
13
+ _userService = userService;
14
+ }
15
+
16
+ [HttpPost]
17
+ public async Task<ActionResult<UserCreateResponse>> CreateUser([FromBody] UserCreateRequest request)
18
+ {
19
+ var response = await _userService.CreateUser(request);
20
+ return Ok(response);
21
+ }
22
+ }
23
+ }
LibraryManagement.Backend/Features/Users/UserService.cs ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Database.Models;
2
+
3
+ namespace LibraryManagement.Backend.Features.Users
4
+ {
5
+ public interface IUserService
6
+ {
7
+ public Task<UserCreateResponse> CreateUser(UserCreateRequest request);
8
+ }
9
+
10
+ public class UserService : IUserService
11
+ {
12
+ private readonly LibraryManagementContext _context;
13
+
14
+ public UserService(LibraryManagementContext context) {
15
+ _context = context;
16
+ }
17
+
18
+ public Task<UserCreateResponse> CreateUser(UserCreateRequest request)
19
+ {
20
+ throw new NotImplementedException();
21
+ }
22
+ }
23
+
24
+ public class UserCreateRequest {
25
+
26
+ }
27
+
28
+ public class UserCreateResponse {
29
+ }
30
+ }
LibraryManagement.Backend/LibraryManagement.Backend.csproj ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <Project Sdk="Microsoft.NET.Sdk.Web">
2
+
3
+ <PropertyGroup>
4
+ <TargetFramework>net8.0</TargetFramework>
5
+ <Nullable>enable</Nullable>
6
+ <ImplicitUsings>enable</ImplicitUsings>
7
+ </PropertyGroup>
8
+
9
+ <ItemGroup>
10
+ <PackageReference Include="BCrypt.Net-Next" Version="4.1.0" />
11
+ <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
12
+ <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
13
+ <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />
14
+ </ItemGroup>
15
+
16
+ <ItemGroup>
17
+ <ProjectReference Include="..\Database\Database.csproj" />
18
+ </ItemGroup>
19
+
20
+ </Project>
LibraryManagement.Backend/LibraryManagement.Backend.http ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ @LibraryManagement.Backend_HostAddress = http://localhost:5199
2
+
3
+ GET {{LibraryManagement.Backend_HostAddress}}/weatherforecast/
4
+ Accept: application/json
5
+
6
+ ###
LibraryManagement.Backend/Program.cs ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Text;
2
+ using Database.Models;
3
+ using LibraryManagement.Backend.Features.Auth;
4
+ using LibraryManagement.Backend.Features.Users;
5
+ using Microsoft.AspNetCore.Authentication.JwtBearer;
6
+ using Microsoft.EntityFrameworkCore;
7
+ using Microsoft.IdentityModel.Tokens;
8
+ using Microsoft.OpenApi.Models;
9
+
10
+ var builder = WebApplication.CreateBuilder(args);
11
+
12
+ builder.Services.AddControllers();
13
+ builder.Services.AddEndpointsApiExplorer();
14
+ builder.Services.AddSwaggerGen(c =>
15
+ {
16
+ c.SwaggerDoc("v1", new OpenApiInfo { Title = "Library Management API", Version = "v1" });
17
+ c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
18
+ {
19
+ Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
20
+ Name = "Authorization",
21
+ In = ParameterLocation.Header,
22
+ Type = SecuritySchemeType.ApiKey,
23
+ Scheme = "Bearer"
24
+ });
25
+ c.AddSecurityRequirement(new OpenApiSecurityRequirement
26
+ {
27
+ {
28
+ new OpenApiSecurityScheme
29
+ {
30
+ Reference = new OpenApiReference
31
+ {
32
+ Type = ReferenceType.SecurityScheme,
33
+ Id = "Bearer"
34
+ }
35
+ },
36
+ new string[] {}
37
+ }
38
+ });
39
+ });
40
+
41
+ builder.Services.AddDbContext<LibraryManagementContext>(options =>
42
+ options.UseSqlServer(builder.Configuration.GetConnectionString("MssqlConnection")));
43
+
44
+ // Register Services
45
+ builder.Services.AddScoped<IAuthService, AuthService>();
46
+ builder.Services.AddScoped<IUserService, UserService>();
47
+
48
+ // Configure JWT Authentication
49
+ var key = Encoding.ASCII.GetBytes(builder.Configuration["Jwt:Secret"] ?? "YourSuperSecretKeyForLibraryManagementSystem_AtLeast32CharsLong");
50
+ builder.Services.AddAuthentication(x =>
51
+ {
52
+ x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
53
+ x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
54
+ })
55
+ .AddJwtBearer(x =>
56
+ {
57
+ x.RequireHttpsMetadata = false;
58
+ x.SaveToken = true;
59
+ x.TokenValidationParameters = new TokenValidationParameters
60
+ {
61
+ ValidateIssuerSigningKey = true,
62
+ IssuerSigningKey = new SymmetricSecurityKey(key),
63
+ ValidateIssuer = true,
64
+ ValidateAudience = true,
65
+ ValidIssuer = builder.Configuration["Jwt:Issuer"],
66
+ ValidAudience = builder.Configuration["Jwt:Audience"],
67
+ ClockSkew = TimeSpan.Zero
68
+ };
69
+ });
70
+
71
+ var app = builder.Build();
72
+
73
+ app.UseSwagger();
74
+ app.UseSwaggerUI();
75
+
76
+ app.UseHttpsRedirection();
77
+
78
+ app.UseAuthentication();
79
+ app.UseAuthorization();
80
+
81
+ app.MapControllers();
82
+
83
+ app.Run();
{LibraryManagement → LibraryManagement.Backend}/Properties/launchSettings.json RENAMED
@@ -4,8 +4,8 @@
4
  "windowsAuthentication": false,
5
  "anonymousAuthentication": true,
6
  "iisExpress": {
7
- "applicationUrl": "http://localhost:64033",
8
- "sslPort": 44305
9
  }
10
  },
11
  "profiles": {
@@ -13,7 +13,8 @@
13
  "commandName": "Project",
14
  "dotnetRunMessages": true,
15
  "launchBrowser": true,
16
- "applicationUrl": "http://localhost:5064",
 
17
  "environmentVariables": {
18
  "ASPNETCORE_ENVIRONMENT": "Development"
19
  }
@@ -22,7 +23,8 @@
22
  "commandName": "Project",
23
  "dotnetRunMessages": true,
24
  "launchBrowser": true,
25
- "applicationUrl": "https://localhost:7277;http://localhost:5064",
 
26
  "environmentVariables": {
27
  "ASPNETCORE_ENVIRONMENT": "Development"
28
  }
@@ -30,6 +32,7 @@
30
  "IIS Express": {
31
  "commandName": "IISExpress",
32
  "launchBrowser": true,
 
33
  "environmentVariables": {
34
  "ASPNETCORE_ENVIRONMENT": "Development"
35
  }
 
4
  "windowsAuthentication": false,
5
  "anonymousAuthentication": true,
6
  "iisExpress": {
7
+ "applicationUrl": "http://localhost:13110",
8
+ "sslPort": 44374
9
  }
10
  },
11
  "profiles": {
 
13
  "commandName": "Project",
14
  "dotnetRunMessages": true,
15
  "launchBrowser": true,
16
+ "launchUrl": "swagger",
17
+ "applicationUrl": "http://localhost:5199",
18
  "environmentVariables": {
19
  "ASPNETCORE_ENVIRONMENT": "Development"
20
  }
 
23
  "commandName": "Project",
24
  "dotnetRunMessages": true,
25
  "launchBrowser": true,
26
+ "launchUrl": "swagger",
27
+ "applicationUrl": "https://localhost:7028;http://localhost:5199",
28
  "environmentVariables": {
29
  "ASPNETCORE_ENVIRONMENT": "Development"
30
  }
 
32
  "IIS Express": {
33
  "commandName": "IISExpress",
34
  "launchBrowser": true,
35
+ "launchUrl": "swagger",
36
  "environmentVariables": {
37
  "ASPNETCORE_ENVIRONMENT": "Development"
38
  }
LibraryManagement.Backend/WeatherForecast.cs ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace LibraryManagement.Backend
2
+ {
3
+ public class WeatherForecast
4
+ {
5
+ public DateOnly Date { get; set; }
6
+
7
+ public int TemperatureC { get; set; }
8
+
9
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
10
+
11
+ public string? Summary { get; set; }
12
+ }
13
+ }
{LibraryManagement → LibraryManagement.Backend}/appsettings.Development.json RENAMED
File without changes
LibraryManagement.Backend/appsettings.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Logging": {
3
+ "LogLevel": {
4
+ "Default": "Information",
5
+ "Microsoft.AspNetCore": "Warning"
6
+ }
7
+ },
8
+ "AllowedHosts": "*",
9
+ "ConnectionStrings": {
10
+ "MssqlConnection": "Server=DESKTOP-BP9A061;Database=LibraryManagement;User Id=sa;Password=sasa@123;TrustServerCertificate=True;"
11
+ },
12
+ "Jwt": {
13
+ "Secret": "YourSuperSecretKeyForLibraryManagementSystem_AtLeast32CharsLong",
14
+ "Issuer": "LibraryManagementSystem",
15
+ "Audience": "LibraryManagementUsers"
16
+ }
17
+ }
LibraryManagement.Frontend/Components/App.razor ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <base href="/" />
8
+ <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
9
+ <link rel="stylesheet" href="app.css" />
10
+ <link rel="stylesheet" href="LibraryManagement.Frontend.styles.css" />
11
+ <link rel="icon" type="image/png" href="favicon.png" />
12
+ <HeadOutlet />
13
+ </head>
14
+
15
+ <body>
16
+ <Routes />
17
+ <script src="_framework/blazor.web.js"></script>
18
+ </body>
19
+
20
+ </html>
LibraryManagement.Frontend/Components/Layout/MainLayout.razor ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @inherits LayoutComponentBase
2
+
3
+ <div class="page">
4
+ <div class="sidebar">
5
+ <NavMenu />
6
+ </div>
7
+
8
+ <main>
9
+ <div class="top-row px-4">
10
+ <a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
11
+ </div>
12
+
13
+ <article class="content px-4">
14
+ @Body
15
+ </article>
16
+ </main>
17
+ </div>
18
+
19
+ <div id="blazor-error-ui">
20
+ An unhandled error has occurred.
21
+ <a href="" class="reload">Reload</a>
22
+ <a class="dismiss">🗙</a>
23
+ </div>
LibraryManagement.Frontend/Components/Layout/MainLayout.razor.css ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .page {
2
+ position: relative;
3
+ display: flex;
4
+ flex-direction: column;
5
+ }
6
+
7
+ main {
8
+ flex: 1;
9
+ }
10
+
11
+ .sidebar {
12
+ background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
13
+ }
14
+
15
+ .top-row {
16
+ background-color: #f7f7f7;
17
+ border-bottom: 1px solid #d6d5d5;
18
+ justify-content: flex-end;
19
+ height: 3.5rem;
20
+ display: flex;
21
+ align-items: center;
22
+ }
23
+
24
+ .top-row ::deep a, .top-row ::deep .btn-link {
25
+ white-space: nowrap;
26
+ margin-left: 1.5rem;
27
+ text-decoration: none;
28
+ }
29
+
30
+ .top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
31
+ text-decoration: underline;
32
+ }
33
+
34
+ .top-row ::deep a:first-child {
35
+ overflow: hidden;
36
+ text-overflow: ellipsis;
37
+ }
38
+
39
+ @media (max-width: 640.98px) {
40
+ .top-row {
41
+ justify-content: space-between;
42
+ }
43
+
44
+ .top-row ::deep a, .top-row ::deep .btn-link {
45
+ margin-left: 0;
46
+ }
47
+ }
48
+
49
+ @media (min-width: 641px) {
50
+ .page {
51
+ flex-direction: row;
52
+ }
53
+
54
+ .sidebar {
55
+ width: 250px;
56
+ height: 100vh;
57
+ position: sticky;
58
+ top: 0;
59
+ }
60
+
61
+ .top-row {
62
+ position: sticky;
63
+ top: 0;
64
+ z-index: 1;
65
+ }
66
+
67
+ .top-row.auth ::deep a:first-child {
68
+ flex: 1;
69
+ text-align: right;
70
+ width: 0;
71
+ }
72
+
73
+ .top-row, article {
74
+ padding-left: 2rem !important;
75
+ padding-right: 1.5rem !important;
76
+ }
77
+ }
78
+
79
+ #blazor-error-ui {
80
+ background: lightyellow;
81
+ bottom: 0;
82
+ box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
83
+ display: none;
84
+ left: 0;
85
+ padding: 0.6rem 1.25rem 0.7rem 1.25rem;
86
+ position: fixed;
87
+ width: 100%;
88
+ z-index: 1000;
89
+ }
90
+
91
+ #blazor-error-ui .dismiss {
92
+ cursor: pointer;
93
+ position: absolute;
94
+ right: 0.75rem;
95
+ top: 0.5rem;
96
+ }
LibraryManagement.Frontend/Components/Layout/NavMenu.razor ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="top-row ps-3 navbar navbar-dark">
2
+ <div class="container-fluid">
3
+ <a class="navbar-brand" href="">LibraryManagement.Frontend</a>
4
+ </div>
5
+ </div>
6
+
7
+ <input type="checkbox" title="Navigation menu" class="navbar-toggler" />
8
+
9
+ <div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
10
+ <nav class="flex-column">
11
+ <div class="nav-item px-3">
12
+ <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
13
+ <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
14
+ </NavLink>
15
+ </div>
16
+
17
+ <div class="nav-item px-3">
18
+ <NavLink class="nav-link" href="counter">
19
+ <span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
20
+ </NavLink>
21
+ </div>
22
+
23
+ <div class="nav-item px-3">
24
+ <NavLink class="nav-link" href="weather">
25
+ <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
26
+ </NavLink>
27
+ </div>
28
+ </nav>
29
+ </div>
30
+
LibraryManagement.Frontend/Components/Layout/NavMenu.razor.css ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .navbar-toggler {
2
+ appearance: none;
3
+ cursor: pointer;
4
+ width: 3.5rem;
5
+ height: 2.5rem;
6
+ color: white;
7
+ position: absolute;
8
+ top: 0.5rem;
9
+ right: 1rem;
10
+ border: 1px solid rgba(255, 255, 255, 0.1);
11
+ background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
12
+ }
13
+
14
+ .navbar-toggler:checked {
15
+ background-color: rgba(255, 255, 255, 0.5);
16
+ }
17
+
18
+ .top-row {
19
+ height: 3.5rem;
20
+ background-color: rgba(0,0,0,0.4);
21
+ }
22
+
23
+ .navbar-brand {
24
+ font-size: 1.1rem;
25
+ }
26
+
27
+ .bi {
28
+ display: inline-block;
29
+ position: relative;
30
+ width: 1.25rem;
31
+ height: 1.25rem;
32
+ margin-right: 0.75rem;
33
+ top: -1px;
34
+ background-size: cover;
35
+ }
36
+
37
+ .bi-house-door-fill-nav-menu {
38
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
39
+ }
40
+
41
+ .bi-plus-square-fill-nav-menu {
42
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
43
+ }
44
+
45
+ .bi-list-nested-nav-menu {
46
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
47
+ }
48
+
49
+ .nav-item {
50
+ font-size: 0.9rem;
51
+ padding-bottom: 0.5rem;
52
+ }
53
+
54
+ .nav-item:first-of-type {
55
+ padding-top: 1rem;
56
+ }
57
+
58
+ .nav-item:last-of-type {
59
+ padding-bottom: 1rem;
60
+ }
61
+
62
+ .nav-item ::deep .nav-link {
63
+ color: #d7d7d7;
64
+ background: none;
65
+ border: none;
66
+ border-radius: 4px;
67
+ height: 3rem;
68
+ display: flex;
69
+ align-items: center;
70
+ line-height: 3rem;
71
+ width: 100%;
72
+ }
73
+
74
+ .nav-item ::deep a.active {
75
+ background-color: rgba(255,255,255,0.37);
76
+ color: white;
77
+ }
78
+
79
+ .nav-item ::deep .nav-link:hover {
80
+ background-color: rgba(255,255,255,0.1);
81
+ color: white;
82
+ }
83
+
84
+ .nav-scrollable {
85
+ display: none;
86
+ }
87
+
88
+ .navbar-toggler:checked ~ .nav-scrollable {
89
+ display: block;
90
+ }
91
+
92
+ @media (min-width: 641px) {
93
+ .navbar-toggler {
94
+ display: none;
95
+ }
96
+
97
+ .nav-scrollable {
98
+ /* Never collapse the sidebar for wide screens */
99
+ display: block;
100
+
101
+ /* Allow sidebar to scroll for tall menus */
102
+ height: calc(100vh - 3.5rem);
103
+ overflow-y: auto;
104
+ }
105
+ }
LibraryManagement.Frontend/Components/Pages/Counter.razor ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @page "/counter"
2
+ @rendermode InteractiveServer
3
+
4
+ <PageTitle>Counter</PageTitle>
5
+
6
+ <h1>Counter</h1>
7
+
8
+ <p role="status">Current count: @currentCount</p>
9
+
10
+ <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
11
+
12
+ @code {
13
+ private int currentCount = 0;
14
+
15
+ private void IncrementCount()
16
+ {
17
+ currentCount++;
18
+ }
19
+ }
LibraryManagement/Views/Shared/Error.cshtml → LibraryManagement.Frontend/Components/Pages/Error.razor RENAMED
@@ -1,15 +1,15 @@
1
- @model ErrorViewModel
2
- @{
3
- ViewData["Title"] = "Error";
4
- }
5
 
6
  <h1 class="text-danger">Error.</h1>
7
  <h2 class="text-danger">An error occurred while processing your request.</h2>
8
 
9
- @if (Model.ShowRequestId)
10
  {
11
  <p>
12
- <strong>Request ID:</strong> <code>@Model.RequestId</code>
13
  </p>
14
  }
15
 
@@ -23,3 +23,14 @@
23
  For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
24
  and restarting the app.
25
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @page "/Error"
2
+ @using System.Diagnostics
3
+
4
+ <PageTitle>Error</PageTitle>
5
 
6
  <h1 class="text-danger">Error.</h1>
7
  <h2 class="text-danger">An error occurred while processing your request.</h2>
8
 
9
+ @if (ShowRequestId)
10
  {
11
  <p>
12
+ <strong>Request ID:</strong> <code>@RequestId</code>
13
  </p>
14
  }
15
 
 
23
  For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
24
  and restarting the app.
25
  </p>
26
+
27
+ @code{
28
+ [CascadingParameter]
29
+ private HttpContext? HttpContext { get; set; }
30
+
31
+ private string? RequestId { get; set; }
32
+ private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
33
+
34
+ protected override void OnInitialized() =>
35
+ RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
36
+ }
LibraryManagement.Frontend/Components/Pages/Home.razor ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ @page "/"
2
+
3
+ <PageTitle>Home</PageTitle>
4
+
5
+ <h1>Hello, world!</h1>
6
+
7
+ Welcome to your new app.
LibraryManagement.Frontend/Components/Pages/Weather.razor ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @page "/weather"
2
+ @attribute [StreamRendering]
3
+
4
+ <PageTitle>Weather</PageTitle>
5
+
6
+ <h1>Weather</h1>
7
+
8
+ <p>This component demonstrates showing data.</p>
9
+
10
+ @if (forecasts == null)
11
+ {
12
+ <p><em>Loading...</em></p>
13
+ }
14
+ else
15
+ {
16
+ <table class="table">
17
+ <thead>
18
+ <tr>
19
+ <th>Date</th>
20
+ <th>Temp. (C)</th>
21
+ <th>Temp. (F)</th>
22
+ <th>Summary</th>
23
+ </tr>
24
+ </thead>
25
+ <tbody>
26
+ @foreach (var forecast in forecasts)
27
+ {
28
+ <tr>
29
+ <td>@forecast.Date.ToShortDateString()</td>
30
+ <td>@forecast.TemperatureC</td>
31
+ <td>@forecast.TemperatureF</td>
32
+ <td>@forecast.Summary</td>
33
+ </tr>
34
+ }
35
+ </tbody>
36
+ </table>
37
+ }
38
+
39
+ @code {
40
+ private WeatherForecast[]? forecasts;
41
+
42
+ protected override async Task OnInitializedAsync()
43
+ {
44
+ // Simulate asynchronous loading to demonstrate streaming rendering
45
+ await Task.Delay(500);
46
+
47
+ var startDate = DateOnly.FromDateTime(DateTime.Now);
48
+ var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
49
+ forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
50
+ {
51
+ Date = startDate.AddDays(index),
52
+ TemperatureC = Random.Shared.Next(-20, 55),
53
+ Summary = summaries[Random.Shared.Next(summaries.Length)]
54
+ }).ToArray();
55
+ }
56
+
57
+ private class WeatherForecast
58
+ {
59
+ public DateOnly Date { get; set; }
60
+ public int TemperatureC { get; set; }
61
+ public string? Summary { get; set; }
62
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
63
+ }
64
+ }
LibraryManagement.Frontend/Components/Routes.razor ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <Router AppAssembly="typeof(Program).Assembly">
2
+ <Found Context="routeData">
3
+ <RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
4
+ <FocusOnNavigate RouteData="routeData" Selector="h1" />
5
+ </Found>
6
+ </Router>
LibraryManagement.Frontend/Components/_Imports.razor ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ @using System.Net.Http
2
+ @using System.Net.Http.Json
3
+ @using Microsoft.AspNetCore.Components.Forms
4
+ @using Microsoft.AspNetCore.Components.Routing
5
+ @using Microsoft.AspNetCore.Components.Web
6
+ @using static Microsoft.AspNetCore.Components.Web.RenderMode
7
+ @using Microsoft.AspNetCore.Components.Web.Virtualization
8
+ @using Microsoft.JSInterop
9
+ @using LibraryManagement.Frontend
10
+ @using LibraryManagement.Frontend.Components
LibraryManagement/LibraryManagement.csproj → LibraryManagement.Frontend/LibraryManagement.Frontend.csproj RENAMED
File without changes
{LibraryManagement → LibraryManagement.Frontend}/Program.cs RENAMED
@@ -1,27 +1,27 @@
 
 
1
  var builder = WebApplication.CreateBuilder(args);
2
 
3
  // Add services to the container.
4
- builder.Services.AddControllersWithViews();
 
5
 
6
  var app = builder.Build();
7
 
8
  // Configure the HTTP request pipeline.
9
  if (!app.Environment.IsDevelopment())
10
  {
11
- app.UseExceptionHandler("/Home/Error");
12
  // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
13
  app.UseHsts();
14
  }
15
 
16
  app.UseHttpsRedirection();
17
- app.UseStaticFiles();
18
 
19
- app.UseRouting();
20
-
21
- app.UseAuthorization();
22
 
23
- app.MapControllerRoute(
24
- name: "default",
25
- pattern: "{controller=Home}/{action=Index}/{id?}");
26
 
27
  app.Run();
 
1
+ using LibraryManagement.Frontend.Components;
2
+
3
  var builder = WebApplication.CreateBuilder(args);
4
 
5
  // Add services to the container.
6
+ builder.Services.AddRazorComponents()
7
+ .AddInteractiveServerComponents();
8
 
9
  var app = builder.Build();
10
 
11
  // Configure the HTTP request pipeline.
12
  if (!app.Environment.IsDevelopment())
13
  {
14
+ app.UseExceptionHandler("/Error", createScopeForErrors: true);
15
  // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
16
  app.UseHsts();
17
  }
18
 
19
  app.UseHttpsRedirection();
 
20
 
21
+ app.UseStaticFiles();
22
+ app.UseAntiforgery();
 
23
 
24
+ app.MapRazorComponents<App>()
25
+ .AddInteractiveServerRenderMode();
 
26
 
27
  app.Run();
LibraryManagement.Frontend/Properties/launchSettings.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "$schema": "http://json.schemastore.org/launchsettings.json",
3
+ "iisSettings": {
4
+ "windowsAuthentication": false,
5
+ "anonymousAuthentication": true,
6
+ "iisExpress": {
7
+ "applicationUrl": "http://localhost:63301",
8
+ "sslPort": 44390
9
+ }
10
+ },
11
+ "profiles": {
12
+ "http": {
13
+ "commandName": "Project",
14
+ "dotnetRunMessages": true,
15
+ "launchBrowser": true,
16
+ "applicationUrl": "http://localhost:5008",
17
+ "environmentVariables": {
18
+ "ASPNETCORE_ENVIRONMENT": "Development"
19
+ }
20
+ },
21
+ "https": {
22
+ "commandName": "Project",
23
+ "dotnetRunMessages": true,
24
+ "launchBrowser": true,
25
+ "applicationUrl": "https://localhost:7187;http://localhost:5008",
26
+ "environmentVariables": {
27
+ "ASPNETCORE_ENVIRONMENT": "Development"
28
+ }
29
+ },
30
+ "IIS Express": {
31
+ "commandName": "IISExpress",
32
+ "launchBrowser": true,
33
+ "environmentVariables": {
34
+ "ASPNETCORE_ENVIRONMENT": "Development"
35
+ }
36
+ }
37
+ }
38
+ }
LibraryManagement.Frontend/appsettings.Development.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Logging": {
3
+ "LogLevel": {
4
+ "Default": "Information",
5
+ "Microsoft.AspNetCore": "Warning"
6
+ }
7
+ }
8
+ }
{LibraryManagement → LibraryManagement.Frontend}/appsettings.json RENAMED
File without changes
LibraryManagement.Frontend/wwwroot/app.css ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html, body {
2
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
3
+ }
4
+
5
+ a, .btn-link {
6
+ color: #006bb7;
7
+ }
8
+
9
+ .btn-primary {
10
+ color: #fff;
11
+ background-color: #1b6ec2;
12
+ border-color: #1861ac;
13
+ }
14
+
15
+ .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
16
+ box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
17
+ }
18
+
19
+ .content {
20
+ padding-top: 1.1rem;
21
+ }
22
+
23
+ h1:focus {
24
+ outline: none;
25
+ }
26
+
27
+ .valid.modified:not([type=checkbox]) {
28
+ outline: 1px solid #26b050;
29
+ }
30
+
31
+ .invalid {
32
+ outline: 1px solid #e50000;
33
+ }
34
+
35
+ .validation-message {
36
+ color: #e50000;
37
+ }
38
+
39
+ .blazor-error-boundary {
40
+ background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
41
+ padding: 1rem 1rem 1rem 3.7rem;
42
+ color: white;
43
+ }
44
+
45
+ .blazor-error-boundary::after {
46
+ content: "An error has occurred."
47
+ }
48
+
49
+ .darker-border-checkbox.form-check-input {
50
+ border-color: #929292;
51
+ }
{LibraryManagement/wwwroot/lib/bootstrap/dist/css → LibraryManagement.Frontend/wwwroot/bootstrap}/bootstrap.min.css RENAMED
File without changes
{LibraryManagement/wwwroot/lib/bootstrap/dist/css → LibraryManagement.Frontend/wwwroot/bootstrap}/bootstrap.min.css.map RENAMED
File without changes
LibraryManagement.Frontend/wwwroot/favicon.png ADDED
LibraryManagement.slnx CHANGED
@@ -1,3 +1,5 @@
1
  <Solution>
2
- <Project Path="LibraryManagement/LibraryManagement.csproj" />
 
 
3
  </Solution>
 
1
  <Solution>
2
+ <Project Path="Database/Database.csproj" Id="1ec23dc7-355d-4456-a503-cfd0fb81cd5c" />
3
+ <Project Path="LibraryManagement.Backend/LibraryManagement.Backend.csproj" Id="82e311b1-ce76-4235-9d5f-0d06a942d038" />
4
+ <Project Path="LibraryManagement.Frontend/LibraryManagement.Frontend.csproj" Id="4209546e-83fd-4d5c-8707-47c86053d9a8" />
5
  </Solution>
LibraryManagement/Controllers/HomeController.cs DELETED
@@ -1,32 +0,0 @@
1
- using LibraryManagement.Models;
2
- using Microsoft.AspNetCore.Mvc;
3
- using System.Diagnostics;
4
-
5
- namespace LibraryManagement.Controllers
6
- {
7
- public class HomeController : Controller
8
- {
9
- private readonly ILogger<HomeController> _logger;
10
-
11
- public HomeController(ILogger<HomeController> logger)
12
- {
13
- _logger = logger;
14
- }
15
-
16
- public IActionResult Index()
17
- {
18
- return View();
19
- }
20
-
21
- public IActionResult Privacy()
22
- {
23
- return View();
24
- }
25
-
26
- [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
27
- public IActionResult Error()
28
- {
29
- return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
30
- }
31
- }
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
LibraryManagement/Models/ErrorViewModel.cs DELETED
@@ -1,9 +0,0 @@
1
- namespace LibraryManagement.Models
2
- {
3
- public class ErrorViewModel
4
- {
5
- public string? RequestId { get; set; }
6
-
7
- public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
8
- }
9
- }
 
 
 
 
 
 
 
 
 
 
LibraryManagement/Views/Home/Index.cshtml DELETED
@@ -1,8 +0,0 @@
1
- @{
2
- ViewData["Title"] = "Home Page";
3
- }
4
-
5
- <div class="text-center">
6
- <h1 class="display-4">Welcome</h1>
7
- <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
8
- </div>
 
 
 
 
 
 
 
 
 
LibraryManagement/Views/Home/Privacy.cshtml DELETED
@@ -1,6 +0,0 @@
1
- @{
2
- ViewData["Title"] = "Privacy Policy";
3
- }
4
- <h1>@ViewData["Title"]</h1>
5
-
6
- <p>Use this page to detail your site's privacy policy.</p>
 
 
 
 
 
 
 
LibraryManagement/Views/Shared/_Layout.cshtml DELETED
@@ -1,49 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>@ViewData["Title"] - LibraryManagement</title>
7
- <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
8
- <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
9
- <link rel="stylesheet" href="~/LibraryManagement.styles.css" asp-append-version="true" />
10
- </head>
11
- <body>
12
- <header>
13
- <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
14
- <div class="container-fluid">
15
- <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">LibraryManagement</a>
16
- <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
17
- aria-expanded="false" aria-label="Toggle navigation">
18
- <span class="navbar-toggler-icon"></span>
19
- </button>
20
- <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
21
- <ul class="navbar-nav flex-grow-1">
22
- <li class="nav-item">
23
- <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
24
- </li>
25
- <li class="nav-item">
26
- <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
27
- </li>
28
- </ul>
29
- </div>
30
- </div>
31
- </nav>
32
- </header>
33
- <div class="container">
34
- <main role="main" class="pb-3">
35
- @RenderBody()
36
- </main>
37
- </div>
38
-
39
- <footer class="border-top footer text-muted">
40
- <div class="container">
41
- &copy; 2026 - LibraryManagement - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
42
- </div>
43
- </footer>
44
- <script src="~/lib/jquery/dist/jquery.min.js"></script>
45
- <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
46
- <script src="~/js/site.js" asp-append-version="true"></script>
47
- @await RenderSectionAsync("Scripts", required: false)
48
- </body>
49
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
LibraryManagement/Views/Shared/_Layout.cshtml.css DELETED
@@ -1,48 +0,0 @@
1
- /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
2
- for details on configuring this project to bundle and minify static web assets. */
3
-
4
- a.navbar-brand {
5
- white-space: normal;
6
- text-align: center;
7
- word-break: break-all;
8
- }
9
-
10
- a {
11
- color: #0077cc;
12
- }
13
-
14
- .btn-primary {
15
- color: #fff;
16
- background-color: #1b6ec2;
17
- border-color: #1861ac;
18
- }
19
-
20
- .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
21
- color: #fff;
22
- background-color: #1b6ec2;
23
- border-color: #1861ac;
24
- }
25
-
26
- .border-top {
27
- border-top: 1px solid #e5e5e5;
28
- }
29
- .border-bottom {
30
- border-bottom: 1px solid #e5e5e5;
31
- }
32
-
33
- .box-shadow {
34
- box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
35
- }
36
-
37
- button.accept-policy {
38
- font-size: 1rem;
39
- line-height: inherit;
40
- }
41
-
42
- .footer {
43
- position: absolute;
44
- bottom: 0;
45
- width: 100%;
46
- white-space: nowrap;
47
- line-height: 60px;
48
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
LibraryManagement/Views/Shared/_ValidationScriptsPartial.cshtml DELETED
@@ -1,2 +0,0 @@
1
- <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
2
- <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
 
 
 
LibraryManagement/Views/_ViewImports.cshtml DELETED
@@ -1,3 +0,0 @@
1
- @using LibraryManagement
2
- @using LibraryManagement.Models
3
- @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers