Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions aspnet-core/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,10 @@ paket-files/
src/Moipone.PublicSite.Web.Mvc/secrets.json
src/Moipone.PublicSite.Web.Host/secrets.json
src/Moipone.PublicSite.Migrator/secrets.json


# Ignore all environment files
.env
.env.*
**/.env
**/.env.*
166 changes: 129 additions & 37 deletions aspnet-core/Generate-AppService.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -86,67 +86,159 @@ namespace $Namespace.$PluralEntityName

public override async Task<${EntityName}Dto> CreateAsync(${EntityName}Dto input)
{
if (input == null)
try
{
throw new UserFriendlyException("$EntityName data cannot be null.");
if (input == null)
{
throw new UserFriendlyException(
"$EntityName data cannot be null.",
Abp.Logging.LogSeverity.Warn
);
}

var entity = ObjectMapper.Map<$EntityName>(input);
var result = await _${EntityLower}Repository.InsertAsync(entity);

return ObjectMapper.Map<${EntityName}Dto>(result);
}
catch (UserFriendlyException)
{
throw;
}
catch (Exception ex)
{
Logger.Error("Error creating $EntityName", ex);
throw new UserFriendlyException(
$"Could not create $EntityName. Error: {ex.Message}",
Abp.Logging.LogSeverity.Error
);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

var entity = ObjectMapper.Map<$EntityName>(input);
var result = await _${EntityLower}Repository.InsertAsync(entity);

return ObjectMapper.Map<${EntityName}Dto>(result);
}

public override async Task<PagedResultDto<${EntityName}Dto>> GetAllAsync(PagedAndSortedResultRequestDto input)
{
var query = Repository.GetAll();
var totalCount = await AsyncQueryableExecuter.CountAsync(query);

var items = await AsyncQueryableExecuter.ToListAsync(
query.OrderBy(x => x.Id)
.Skip(input.SkipCount)
.Take(input.MaxResultCount)
);

return new PagedResultDto<${EntityName}Dto>(
totalCount,
ObjectMapper.Map<List<${EntityName}Dto>>(items)
);
try
{
var query = Repository.GetAll();
var totalCount = await AsyncQueryableExecuter.CountAsync(query);

var items = await AsyncQueryableExecuter.ToListAsync(
query.OrderBy(x => x.Id)
.Skip(input.SkipCount)
.Take(input.MaxResultCount)
);

return new PagedResultDto<${EntityName}Dto>(
totalCount,
ObjectMapper.Map<List<${EntityName}Dto>>(items)
);
}
catch (Exception ex)
{
Logger.Error("Error retrieving $PluralEntityName", ex);
throw new UserFriendlyException(
$"Could not retrieve $PluralEntityName. Error: {ex.Message}",
Abp.Logging.LogSeverity.Error
);
}
}

public override async Task<${EntityName}Dto> GetAsync(EntityDto<Guid> input)
{
if (input == null || input.Id == Guid.Empty)
try
{
throw new UserFriendlyException("Invalid ID.");
if (input == null || input.Id == Guid.Empty)
{
throw new UserFriendlyException(
"Invalid $EntityName ID.",
Abp.Logging.LogSeverity.Warn
);
}

var entity = await _${EntityLower}Repository.GetAsync(input.Id);

if (entity == null)
{
throw new UserFriendlyException(
"$EntityName not found.",
Abp.Logging.LogSeverity.Warn
);
}

return ObjectMapper.Map<${EntityName}Dto>(entity);
}
catch (UserFriendlyException)
{
throw;
}
catch (Exception ex)
{
Logger.Error($"Error retrieving $EntityName with ID {input?.Id}", ex);
throw new UserFriendlyException(
$"Could not retrieve $EntityName. Error: {ex.Message}",
Abp.Logging.LogSeverity.Error
);
}

var entity = await _${EntityLower}Repository.GetAsync(input.Id);
return ObjectMapper.Map<${EntityName}Dto>(entity);
}

public override async Task<${EntityName}Dto> UpdateAsync(${EntityName}Dto input)
{
if (input == null || input.Id == Guid.Empty)
try
{
throw new UserFriendlyException("Invalid ID.");
if (input == null || input.Id == Guid.Empty)
{
throw new UserFriendlyException(
"Invalid $EntityName data.",
Abp.Logging.LogSeverity.Warn
);
}

var entity = await _${EntityLower}Repository.GetAsync(input.Id);
ObjectMapper.Map(input, entity);

var updated = await _${EntityLower}Repository.UpdateAsync(entity);
return ObjectMapper.Map<${EntityName}Dto>(updated);
}
catch (UserFriendlyException)
{
throw;
}
catch (Exception ex)
{
Logger.Error($"Error updating $EntityName with ID {input?.Id}", ex);
throw new UserFriendlyException(
$"Could not update $EntityName. Error: {ex.Message}",
Abp.Logging.LogSeverity.Error
);
}

var entity = await _${EntityLower}Repository.GetAsync(input.Id);
ObjectMapper.Map(input, entity);

var updated = await _${EntityLower}Repository.UpdateAsync(entity);
return ObjectMapper.Map<${EntityName}Dto>(updated);
}

public override async Task DeleteAsync(EntityDto<Guid> input)
{
if (input == null || input.Id == Guid.Empty)
try
{
throw new UserFriendlyException("Invalid ID.");
if (input == null || input.Id == Guid.Empty)
{
throw new UserFriendlyException(
"Invalid $EntityName ID.",
Abp.Logging.LogSeverity.Warn
);
}

await _${EntityLower}Repository.DeleteAsync(input.Id);
}
catch (UserFriendlyException)
{
throw;
}
catch (Exception ex)
{
Logger.Error($"Error deleting $EntityName with ID {input?.Id}", ex);
throw new UserFriendlyException(
$"Could not delete $EntityName. Error: {ex.Message}",
Abp.Logging.LogSeverity.Error
);
}

await _${EntityLower}Repository.DeleteAsync(input.Id);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ public class AddressDto : EntityDto<Guid>
public string Suburb { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Province { get; set; }
public string Country { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.UI;
using Moipone.PublicSite.Domain.CourseApplications;
using Microsoft.EntityFrameworkCore;
using Moipone.PublicSite.CourseApplications.Dto;
using Moipone.PublicSite.Domain.CourseApplications;
using Moipone.PublicSite.Domain.ShortCourses;
using Moipone.PublicSite.Domain.Students;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Authorization;

namespace Moipone.PublicSite.CourseApplications
{
Expand All @@ -17,11 +20,15 @@
ICourseApplicationAppService
{
private readonly IRepository<CourseApplication, Guid> _courseApplicationRepository;
private readonly IRepository<ShortCourse, Guid> _shortCourseRepository;
private readonly IRepository<Student, Guid> _studentRepository;

public CourseApplicationAppService(IRepository<CourseApplication, Guid> courseApplicationRepository)
public CourseApplicationAppService(IRepository<CourseApplication, Guid> courseApplicationRepository, IRepository<ShortCourse, Guid> shortCourseRepository, IRepository<Student, Guid> studentRepository)
: base(courseApplicationRepository)
{
_courseApplicationRepository = courseApplicationRepository;
_shortCourseRepository = shortCourseRepository;
_studentRepository = studentRepository;
}

public override async Task<CourseApplicationDto> CreateAsync(CourseApplicationDto input)
Expand All @@ -31,7 +38,24 @@
throw new UserFriendlyException("CourseApplication data cannot be null.");
}

if (!input.StudentId.HasValue || !input.ShortCourseId.HasValue)
{
throw new UserFriendlyException("Student and Course are required.");
}

var alreadyApplied = await _courseApplicationRepository
.FirstOrDefaultAsync(x =>
x.StudentId == input.StudentId &&
x.ShortCourseId == input.ShortCourseId
);

if (alreadyApplied != null)
{
throw new UserFriendlyException("You have already applied for this course.");
}

var entity = ObjectMapper.Map<CourseApplication>(input);

var result = await _courseApplicationRepository.InsertAsync(entity);

return ObjectMapper.Map<CourseApplicationDto>(result);
Expand Down Expand Up @@ -104,30 +128,53 @@
}

[AbpAuthorize]
public async Task<CourseApplicationDto> ApproveApplication(Guid input, string? reason)

Check warning on line 131 in aspnet-core/src/Moipone.PublicSite.Application/CourseApplications/CourseApplicationAppService.cs

View workflow job for this annotation

GitHub Actions / Build Stage

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (input == Guid.Empty)
{
throw new UserFriendlyException("Invalid Application ID.");
}

var application = await _courseApplicationRepository.GetAsync(input);

if (application.Status == RefListApplicationStatus.Approved)
{
throw new UserFriendlyException("Application is already approved.");

var shortCourse = await _shortCourseRepository
.GetAll()
.Include(c => c.EnrolledStudents)
.FirstOrDefaultAsync(c => c.Id == application.ShortCourseId);

if (shortCourse == null)
throw new UserFriendlyException("Short course not found.");

if (shortCourse.EnrolledStudents.Count >= shortCourse.Capacity)
{
application.Status = RefListApplicationStatus.Declined;
application.DecisionDate = DateTime.UtcNow;
application.DecisionReason = "Course is full. Application declined.";
await _courseApplicationRepository.UpdateAsync(application);
throw new UserFriendlyException("Course is already full.");
}

var student = await _studentRepository.GetAsync(application.StudentId);


if (shortCourse.EnrolledStudents.Any(s => s.Id == student.Id))
throw new UserFriendlyException("Student already enrolled.");

shortCourse.EnrolledStudents.Add(student);

application.Status = RefListApplicationStatus.Approved;
application.DecisionDate = DateTime.UtcNow;
application.DecisionReason = reason ?? "Application approved";

await _shortCourseRepository.UpdateAsync(shortCourse);
var updated = await _courseApplicationRepository.UpdateAsync(application);

return ObjectMapper.Map<CourseApplicationDto>(updated);
}

[AbpAuthorize]
public async Task<CourseApplicationDto> RejectApplication(Guid input, string? reason)

Check warning on line 177 in aspnet-core/src/Moipone.PublicSite.Application/CourseApplications/CourseApplicationAppService.cs

View workflow job for this annotation

GitHub Actions / Build Stage

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (input == Guid.Empty)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class ShortCourseDto : EntityDto<Guid>
public bool? IsActive { get; set; }
public DateTime? StartDate { get; set; }
public TimeSpan? Duration { get; set; }
public string? DisplayIcon { get; set; }
public ICollection<string>? Features { get; set; }
#endregion

#region Enrollment Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ public interface IShortCourseAppService : IAsyncCrudAppService<ShortCourseDto, G
Task<ShortCourseDto> CloseApplicationsAsync(Guid id);
Task<ShortCourseDto> ReopenApplicationsAsync(Guid id);
Task<List<ShortCourseDto>> GetOpenCoursesAsync();
Task<int> GetCurrentCapacityAsync(Guid id);
}
}
Loading
Loading