Skip to content

Commit d363a73

Browse files
committed
Refactor DTOs and update course-related logic
Introduced `CourseReadByIdDTO` with additional properties for detailed course information. Updated `CourseReadDTO` to simplify its structure. Replaced `CourseReadDTO` with `CourseReadByIdDTO` across controllers, caching logic, and `GetStudentCoursesDTO`. Adjusted AutoMapper profiles for new mappings. Modified `CreateCourse` and `UpdateCourse` methods to return `CourseReadByIdDTO`. Updated namespaces and performed general refactoring for consistency.
1 parent ef832fe commit d363a73

6 files changed

Lines changed: 59 additions & 27 deletions

File tree

Controllers/CourseController.cs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using AskAMuslimAPI.Enums;
1+
using AskAMuslimAPI.DTOs.CourseDTOs;
2+
using AskAMuslimAPI.Enums;
23
using AutoMapper;
34
using EdufyAPI.DTOs;
45
using EdufyAPI.DTOs.CourseDTOs;
@@ -81,14 +82,14 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourses()
8182
/// <param name="id">The unique identifier of the course.</param>
8283
/// <returns>The course details if found; otherwise, NotFound.</returns>
8384
[HttpGet("{id}")]
84-
public async Task<ActionResult<CourseReadDTO>> GetCourseById(string id)
85+
public async Task<ActionResult<CourseReadByIdDTO>> GetCourseById(string id)
8586
{
8687
const string cacheKeyPrefix = "course_"; // Cache prefix for individual course.
8788
var cacheKey = $"{cacheKeyPrefix}{id}";
8889

8990
try
9091
{
91-
var courseDto = await _memoryCache.GetDataAsync<CourseReadDTO>(cacheKey);
92+
var courseDto = await _memoryCache.GetDataAsync<CourseReadByIdDTO>(cacheKey);
9293

9394
if (courseDto == null)
9495
{
@@ -97,7 +98,7 @@ public async Task<ActionResult<CourseReadDTO>> GetCourseById(string id)
9798
if (course == null)
9899
return NotFound("Course not found.");
99100

100-
courseDto = _mapper.Map<CourseReadDTO>(course);
101+
courseDto = _mapper.Map<CourseReadByIdDTO>(course);
101102
courseDto.ThumbnailUrl = ConstructFileUrlHelper.ConstructFileUrl(Request, ThumbnailsFolderName, courseDto.ThumbnailUrl);
102103

103104
await _memoryCache.SetDataAsync(cacheKey, courseDto, DateTimeOffset.Now.AddMinutes(5));
@@ -115,14 +116,14 @@ public async Task<ActionResult<CourseReadDTO>> GetCourseById(string id)
115116
}
116117

117118
[HttpGet("ByName/{categoryName}")]
118-
public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourseByCategoryName(string categoryName)
119+
public async Task<ActionResult<IEnumerable<CourseReadByIdDTO>>> GetCourseByCategoryName(string categoryName)
119120
{
120121
const string cacheKeyPrefix = "course_category_name_";
121122
var cacheKey = $"{cacheKeyPrefix}{categoryName.ToLower()}";
122123

123124
try
124125
{
125-
var courseDtos = await _memoryCache.GetDataAsync<IEnumerable<CourseReadDTO>>(cacheKey);
126+
var courseDtos = await _memoryCache.GetDataAsync<IEnumerable<CourseReadByIdDTO>>(cacheKey);
126127
if (courseDtos == null)
127128
{
128129
if (!Enum.TryParse(typeof(CourseCategory), categoryName, true, out var categoryEnum))
@@ -134,9 +135,9 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourseByCategoryN
134135
.GetByCondition(c => c.Category == category);
135136

136137
if (!courses.Any())
137-
return Ok(Enumerable.Empty<CourseReadDTO>());
138+
return Ok(Enumerable.Empty<CourseReadByIdDTO>());
138139

139-
courseDtos = _mapper.Map<IEnumerable<CourseReadDTO>>(courses);
140+
courseDtos = _mapper.Map<IEnumerable<CourseReadByIdDTO>>(courses);
140141

141142
foreach (var courseDto in courseDtos)
142143
{
@@ -159,14 +160,14 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourseByCategoryN
159160

160161
// Get Courses by its Level
161162
[HttpGet("ByLevelName/{levelName}")]
162-
public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourseByLevelName(string levelName)
163+
public async Task<ActionResult<IEnumerable<CourseReadByIdDTO>>> GetCourseByLevelName(string levelName)
163164
{
164165
const string cacheKeyPrefix = "course_level_name_";
165166
var cacheKey = $"{cacheKeyPrefix}{levelName.ToLower()}";
166167

167168
try
168169
{
169-
var courseDtos = await _memoryCache.GetDataAsync<IEnumerable<CourseReadDTO>>(cacheKey);
170+
var courseDtos = await _memoryCache.GetDataAsync<IEnumerable<CourseReadByIdDTO>>(cacheKey);
170171
if (courseDtos == null)
171172
{
172173
if (!Enum.TryParse(typeof(CourseLevel), levelName, true, out var levelEnum))
@@ -178,9 +179,9 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourseByLevelName
178179
.GetByCondition(c => c.Level == level);
179180

180181
if (!courses.Any())
181-
return Ok(Enumerable.Empty<CourseReadDTO>());
182+
return Ok(Enumerable.Empty<CourseReadByIdDTO>());
182183

183-
courseDtos = _mapper.Map<IEnumerable<CourseReadDTO>>(courses);
184+
courseDtos = _mapper.Map<IEnumerable<CourseReadByIdDTO>>(courses);
184185

185186
foreach (var courseDto in courseDtos)
186187
{
@@ -207,12 +208,12 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetCourseByLevelName
207208
/// <param name="instructorId">The unique identifier of the instructor.</param>
208209
/// <returns>A list of courses assigned to the instructor.</returns>
209210
[HttpGet("{instructorId}")]
210-
public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetInstructorCourses(string instructorId)
211+
public async Task<ActionResult<IEnumerable<CourseReadByIdDTO>>> GetInstructorCourses(string instructorId)
211212
{
212213
const string cacheKeyPrefix = "instructor_courses_"; // Cache prefix for courses by instructor.
213214
var cacheKey = $"{cacheKeyPrefix}{instructorId}";
214215

215-
var courseDtos = await _memoryCache.GetDataAsync<IEnumerable<CourseReadDTO>>(cacheKey);
216+
var courseDtos = await _memoryCache.GetDataAsync<IEnumerable<CourseReadByIdDTO>>(cacheKey);
216217

217218
try
218219
{
@@ -221,9 +222,9 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetInstructorCourses
221222
// Cache is empty, so retrieve from database.
222223
var courses = await _unitOfWork.CourseRepository.GetByCondition(c => c.InstructorId == instructorId);
223224
if (!courses.Any())
224-
return Ok(Enumerable.Empty<CourseReadDTO>());
225+
return Ok(Enumerable.Empty<CourseReadByIdDTO>());
225226

226-
courseDtos = _mapper.Map<IEnumerable<CourseReadDTO>>(courses);
227+
courseDtos = _mapper.Map<IEnumerable<CourseReadByIdDTO>>(courses);
227228
foreach (var courseDto in courseDtos)
228229
{
229230
courseDto.ThumbnailUrl = ConstructFileUrlHelper.ConstructFileUrl(Request, ThumbnailsFolderName, courseDto.ThumbnailUrl);
@@ -249,7 +250,7 @@ public async Task<ActionResult<IEnumerable<CourseReadDTO>>> GetInstructorCourses
249250
/// <param name="courseCreateDto">The course creation request object.</param>
250251
/// <returns>The created course details.</returns>
251252
[HttpPost]
252-
public async Task<ActionResult<CourseReadDTO>> CreateCourse([FromForm] CourseCreateDTO courseCreateDto)
253+
public async Task<ActionResult<CourseReadByIdDTO>> CreateCourse([FromForm] CourseCreateDTO courseCreateDto)
253254
{
254255
if (!ModelState.IsValid) return BadRequest(ModelState);
255256

@@ -263,7 +264,7 @@ public async Task<ActionResult<CourseReadDTO>> CreateCourse([FromForm] CourseCre
263264
course.ThumbnailUrl = imageUrl;
264265
await _unitOfWork.CourseRepository.AddAsync(course);
265266
await _unitOfWork.SaveChangesAsync();
266-
var courseReadDto = _mapper.Map<CourseReadDTO>(course);
267+
var courseReadDto = _mapper.Map<CourseReadByIdDTO>(course);
267268

268269
// Invalidate the cache for all courses after a new course is created.
269270
await _memoryCache.RemoveDataAsync("all_courses");
@@ -308,7 +309,7 @@ public async Task<IActionResult> UpdateCourse(string id, [FromForm] CourseUpdate
308309
// Invalidate the cache for all courses after an update.
309310
await _memoryCache.RemoveDataAsync("all_courses");
310311

311-
return Ok(_mapper.Map<CourseReadDTO>(course));
312+
return Ok(_mapper.Map<CourseReadByIdDTO>(course));
312313
}
313314
catch (Exception ex)
314315
{

Controllers/EnrollmentController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,15 @@ public async Task<IActionResult> GetEnrolledCoursesByStudent(string studentId)
109109
var cacheKey = $"student-courses-{studentId}";
110110
try
111111
{
112-
var courseDtos = await _cache.GetDataAsync<IEnumerable<CourseReadDTO>>(cacheKey);
112+
var courseDtos = await _cache.GetDataAsync<IEnumerable<CourseReadByIdDTO>>(cacheKey);
113113

114114
if (courseDtos == null)
115115
{
116116
var enrollments = await _unitOfWork.EnrollmentRepository.GetByCondition(e => e.StudentId == studentId);
117117
if (!enrollments.Any())
118118
return NotFound("No enrollments found for this student.");
119119

120-
courseDtos = _mapper.Map<IEnumerable<CourseReadDTO>>(enrollments.Select(e => e.Course));
120+
courseDtos = _mapper.Map<IEnumerable<CourseReadByIdDTO>>(enrollments.Select(e => e.Course));
121121
await _cache.SetDataAsync(cacheKey, courseDtos, DateTimeOffset.Now.AddMinutes(10));
122122
}
123123

DTOs/AutoMapperProfiles.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using AutoMapper;
1+
using AskAMuslimAPI.DTOs.CourseDTOs;
2+
using AutoMapper;
23
using EduConnectAPI.Models;
34
using EdufyAPI.DTOs.CertificateDTOs;
45
using EdufyAPI.DTOs.CourseDTOs;
@@ -68,11 +69,14 @@ public AutoMapperProfiles()
6869
#endregion
6970

7071
#region Course AutoMapper
71-
CreateMap<Course, CourseReadDTO>();
72+
CreateMap<Course, CourseReadByIdDTO>().
73+
ForMember(dest => dest.InstructorName, opt => opt.MapFrom(src => src.Instructor.FullName));
7274
//.ForMember(dest => dest.NumberOfStudentsEnrolled, opt => opt.MapFrom(src => src.NumberOfStudentsEnrolled));
7375
CreateMap<CourseCreateDTO, Course>();
7476
CreateMap<CourseUpdateDTO, Course>()
7577
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)); //This ensures only non-null properties are mapped, preventing overwriting existing values with null.
78+
CreateMap<Course, CourseReadDTO>().
79+
ForMember(dest => dest.InstructorName, opt => opt.MapFrom(src => src.Instructor.FullName));
7680

7781

7882
#endregion
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using AskAMuslimAPI.Enums;
2+
using EdufyAPI.DTOs.LessonDTOs;
3+
4+
namespace EdufyAPI.DTOs
5+
{
6+
public class CourseReadByIdDTO
7+
{
8+
public string Id { get; set; }
9+
public string Title { get; set; } = string.Empty;
10+
public string Description { get; set; } = string.Empty;
11+
public string ThumbnailUrl { get; set; } = string.Empty;
12+
13+
public CourseCategory Category { get; set; }
14+
//public string CategoryName => Category.ToString();
15+
16+
public CourseLevel Level { get; set; }
17+
18+
public string InstructorID { get; set; }
19+
20+
public string InstructorName { get; set; } = string.Empty;
21+
public ICollection<LessonReadDTO> Lessons { get; set; }
22+
23+
24+
public int NumberOfLessons { get; set; } = 0;
25+
26+
public int NumberOfStudentsEnrolled { get; set; } = 0;
27+
}
28+
}

DTOs/CourseDTOs/CourseReadDTO.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using AskAMuslimAPI.Enums;
2-
using EdufyAPI.DTOs.LessonDTOs;
32

4-
namespace EdufyAPI.DTOs
3+
namespace AskAMuslimAPI.DTOs.CourseDTOs
54
{
65
public class CourseReadDTO
76
{
@@ -16,8 +15,8 @@ public class CourseReadDTO
1615
public CourseLevel Level { get; set; }
1716

1817
public string InstructorID { get; set; }
19-
public ICollection<LessonReadDTO> Lessons { get; set; }
2018

19+
public string InstructorName { get; set; } = string.Empty;
2120

2221
public int NumberOfLessons { get; set; } = 0;
2322

DTOs/StudentDTOs/GetStudentCoursesDTO.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public class GetStudentCoursesDTO
66

77
//public Dictionary<string, string> Courses { get; set; }
88

9-
public List<CourseReadDTO> courses { get; set; } = new List<CourseReadDTO>();
9+
public List<CourseReadByIdDTO> courses { get; set; } = new List<CourseReadByIdDTO>();
1010

1111
//public List<string> CoursesTitle { get; set; } = new List<string>();
1212

0 commit comments

Comments
 (0)