Skip to content

Commit bcc8790

Browse files
committed
profile work
1 parent 751bf10 commit bcc8790

39 files changed

+809
-45
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
using api.Data;
2+
using api.Models;
3+
using api.Repositories;
4+
using Microsoft.AspNetCore.Http;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.EntityFrameworkCore;
7+
8+
namespace api.Controllers
9+
{
10+
[Route("api/[controller]")]
11+
[ApiController]
12+
public class ImageController : ControllerBase
13+
{
14+
private readonly IImageRepository _repository;
15+
private readonly AuthDbContext _context;
16+
17+
public ImageController(IImageRepository repository, AuthDbContext context)
18+
{
19+
_repository = repository;
20+
_context = context;
21+
}
22+
23+
[HttpPost]
24+
public async Task<IActionResult> Upload([FromForm] IFormFile file, [FromForm] string name, [FromForm] string category)
25+
{
26+
if (file == null || file.Length == 0)
27+
{
28+
return BadRequest("No file uploaded.");
29+
}
30+
31+
using var memoryStream = new MemoryStream();
32+
await file.CopyToAsync(memoryStream);
33+
34+
var image = new Image
35+
{
36+
Name = name,
37+
Category = category,
38+
ContentType = file.ContentType,
39+
Data = memoryStream.ToArray()
40+
};
41+
42+
var createdImage = await _repository.CreateAsync(image);
43+
return CreatedAtAction(nameof(GetById), new { id = createdImage.Id }, createdImage);
44+
}
45+
46+
[HttpGet("{id}")]
47+
public async Task<IActionResult> GetById(Guid id)
48+
{
49+
var image = await _repository.GetByIdAsync(id);
50+
if (image == null)
51+
{
52+
return NotFound();
53+
}
54+
55+
return File(image.Data, image.ContentType);
56+
}
57+
58+
[HttpGet]
59+
public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 10)
60+
{
61+
if (page < 1 || pageSize < 1)
62+
{
63+
return BadRequest("Page and pageSize must be greater than 0.");
64+
}
65+
66+
var pagedImages = await _repository.GetAllAsync(page, pageSize);
67+
68+
var response = new PageResponse<object>
69+
{
70+
Items = pagedImages.Items.Select(i => new
71+
{
72+
i.Id,
73+
i.Name,
74+
i.Category,
75+
i.ContentType,
76+
i.CreatedAt,
77+
i.UpdatedAt,
78+
Base64 = $"data:{i.ContentType};base64,{Convert.ToBase64String(i.Data)}"
79+
}),
80+
Page = pagedImages.Page,
81+
PageSize = pagedImages.PageSize,
82+
TotalCount = pagedImages.TotalCount
83+
};
84+
85+
return Ok(response);
86+
}
87+
88+
[HttpGet("category/{category}")]
89+
public async Task<IActionResult> GetByCategory(string category, [FromQuery] int page = 1, [FromQuery] int pageSize = 10)
90+
{
91+
if (page < 1 || pageSize < 1)
92+
{
93+
return BadRequest("Page and pageSize must be greater than 0.");
94+
}
95+
96+
var pagedImages = await _repository.GetByCategoryAsync(category, page, pageSize);
97+
var response = new PageResponse<object>
98+
{
99+
Items = pagedImages.Items.Select(i => new { i.Id, i.Name, i.Category, i.ContentType, i.CreatedAt, i.UpdatedAt }),
100+
Page = pagedImages.Page,
101+
PageSize = pagedImages.PageSize,
102+
TotalCount = pagedImages.TotalCount
103+
};
104+
105+
return Ok(response);
106+
}
107+
108+
[HttpPut("{id}")]
109+
public async Task<IActionResult> Update(Guid id, [FromForm] IFormFile file, [FromForm] string name, [FromForm] string category)
110+
{
111+
if (file == null || file.Length == 0)
112+
{
113+
return BadRequest("No file uploaded.");
114+
}
115+
116+
using var memoryStream = new MemoryStream();
117+
await file.CopyToAsync(memoryStream);
118+
119+
var image = new Image
120+
{
121+
Id = id,
122+
Name = name,
123+
Category = category,
124+
ContentType = file.ContentType,
125+
Data = memoryStream.ToArray()
126+
};
127+
128+
var updatedImage = await _repository.UpdateAsync(image);
129+
if (updatedImage == null)
130+
{
131+
return NotFound();
132+
}
133+
134+
return Ok(updatedImage);
135+
}
136+
137+
[HttpDelete("{id}")]
138+
public async Task<IActionResult> Delete(Guid id)
139+
{
140+
var deleted = await _repository.DeleteAsync(id);
141+
if (!deleted)
142+
{
143+
return NotFound();
144+
}
145+
146+
return NoContent();
147+
}
148+
149+
[HttpGet("categories")]
150+
public async Task<IActionResult> GetAllCategory()
151+
{
152+
var categories = await _context.Images
153+
.Select(img => img.Category)
154+
.Distinct()
155+
.ToListAsync();
156+
157+
return Ok(categories);
158+
}
159+
160+
}
161+
}

api/api/Data/AuthDbContext.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,20 @@ public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options) {
2323
/// </summary>
2424
public DbSet<RefreshToken> RefreshTokens { get; set; }
2525
public DbSet<LoginAttempt> LoginAttempts { get; set; }
26+
public DbSet<Image> Images { get; set; }
27+
28+
protected override void OnModelCreating(ModelBuilder modelBuilder)
29+
{
30+
modelBuilder.Entity<Image>()
31+
.HasKey(i => i.Id);
32+
33+
modelBuilder.Entity<Image>()
34+
.Property(i => i.Data)
35+
.HasColumnType("varbinary(max)");
36+
37+
modelBuilder.Entity<Image>()
38+
.Property(i => i.Category)
39+
.HasMaxLength(50); // Limit category length
40+
}
2641
}
2742
}

api/api/Data/PageResponse.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace api.Data
2+
{
3+
public class PageResponse<T>
4+
{
5+
public IEnumerable<T> Items { get; set; } = Enumerable.Empty<T>();
6+
public int Page { get; set; }
7+
public int PageSize { get; set; }
8+
public int TotalCount { get; set; }
9+
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
10+
}
11+
}

api/api/Models/Image.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace api.Models
2+
{
3+
public class Image
4+
{
5+
public Guid Id { get; set; }
6+
public string Name { get; set; } = string.Empty;
7+
public string Category { get; set; } = string.Empty; // New Category field
8+
public string ContentType { get; set; } = string.Empty;
9+
public byte[] Data { get; set; } = Array.Empty<byte>();
10+
public DateTime CreatedAt { get; set; }
11+
public DateTime? UpdatedAt { get; set; }
12+
}
13+
}

api/api/Program.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using api.Data;
2+
using api.Repositories;
23
using api.Services;
34
using Microsoft.AspNetCore.Authentication.JwtBearer;
45
using Microsoft.EntityFrameworkCore;
@@ -31,8 +32,9 @@ public static void Main(string[] args)
3132

3233
// Token service for JWT and refresh token management
3334
builder.Services.AddScoped<iTokenService, TokenService>();
34-
3535
builder.Services.AddHttpClient<TokenService>();
36+
// Register repository
37+
builder.Services.AddScoped<IImageRepository, ImageRepository>();
3638

3739
// JWT Authentication configuration
3840
var jwtKey = builder.Configuration["Jwt:Key"]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using api.Data;
2+
using api.Models;
3+
4+
namespace api.Repositories
5+
{
6+
public interface IImageRepository
7+
{
8+
Task<Image> CreateAsync(Image image);
9+
Task<Image?> GetByIdAsync(Guid id);
10+
Task<PageResponse<Image>> GetAllAsync(int page, int pageSize); // Modified for pagination
11+
Task<PageResponse<Image>> GetByCategoryAsync(string category, int page, int pageSize); // Modified for pagination
12+
Task<Image?> UpdateAsync(Image image);
13+
Task<bool> DeleteAsync(Guid id);
14+
}
15+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using api.Data;
2+
using api.Models;
3+
using Microsoft.AspNetCore.Mvc.RazorPages;
4+
using Microsoft.EntityFrameworkCore;
5+
6+
namespace api.Repositories
7+
{
8+
public class ImageRepository : IImageRepository
9+
{
10+
private readonly AuthDbContext _context;
11+
12+
public ImageRepository(AuthDbContext context)
13+
{
14+
_context = context;
15+
}
16+
17+
public async Task<Image> CreateAsync(Image image)
18+
{
19+
image.Id = Guid.NewGuid();
20+
image.CreatedAt = DateTime.UtcNow;
21+
_context.Images.Add(image);
22+
await _context.SaveChangesAsync();
23+
return image;
24+
}
25+
26+
public async Task<Image?> GetByIdAsync(Guid id)
27+
{
28+
return await _context.Images.FindAsync(id);
29+
}
30+
31+
public async Task<PageResponse<Image>> GetAllAsync(int page, int pageSize)
32+
{
33+
var totalCount = await _context.Images.CountAsync();
34+
var images = await _context.Images
35+
.Skip((page - 1) * pageSize)
36+
.Take(pageSize)
37+
.ToListAsync();
38+
39+
return new PageResponse<Image>
40+
{
41+
Items = images,
42+
Page = page,
43+
PageSize = pageSize,
44+
TotalCount = totalCount
45+
};
46+
}
47+
48+
public async Task<PageResponse<Image>> GetByCategoryAsync(string category, int page, int pageSize)
49+
{
50+
var totalCount = await _context.Images
51+
.Where(i => i.Category == category)
52+
.CountAsync();
53+
54+
var images = await _context.Images
55+
.Where(i => i.Category == category)
56+
.Skip((page - 1) * pageSize)
57+
.Take(pageSize)
58+
.ToListAsync();
59+
60+
return new PageResponse<Image>
61+
{
62+
Items = images,
63+
Page = page,
64+
PageSize = pageSize,
65+
TotalCount = totalCount
66+
};
67+
}
68+
69+
public async Task<Image?> UpdateAsync(Image image)
70+
{
71+
var existingImage = await _context.Images.FindAsync(image.Id);
72+
if (existingImage == null)
73+
{
74+
return null;
75+
}
76+
77+
existingImage.Name = image.Name;
78+
existingImage.Category = image.Category;
79+
existingImage.ContentType = image.ContentType;
80+
existingImage.Data = image.Data;
81+
existingImage.UpdatedAt = DateTime.UtcNow;
82+
83+
await _context.SaveChangesAsync();
84+
return existingImage;
85+
}
86+
87+
public async Task<bool> DeleteAsync(Guid id)
88+
{
89+
var image = await _context.Images.FindAsync(id);
90+
if (image == null)
91+
{
92+
return false;
93+
}
94+
95+
_context.Images.Remove(image);
96+
await _context.SaveChangesAsync();
97+
return true;
98+
}
99+
}
100+
}

api/api/api.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,8 @@
2626
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.0" />
2727
</ItemGroup>
2828

29+
<ItemGroup>
30+
<Folder Include="Migrations\" />
31+
</ItemGroup>
32+
2933
</Project>

web/.hintrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
{
99
"label": "off"
1010
}
11+
],
12+
"axe/text-alternatives": [
13+
"default",
14+
{
15+
"image-alt": "off"
16+
}
1117
]
1218
}
1319
}

web/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)