Refactored DTOs to use AutoMapper instead of manual mapping and made some additional improvements and fixes.
Added : GetAllSurveys&DeleteUser.
This commit is contained in:
2025-02-07 06:40:57 -08:00
parent 272ef7194e
commit 3aabe1a367
214 changed files with 10555 additions and 262 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -24,9 +24,9 @@ namespace survey_beta.Controllers
}
[HttpGet("export/{surveyId}")]
public IActionResult ExportSurveyData(string surveyId)
public async Task<IActionResult> ExportSurveyData(string surveyId)
{
return _analyticsServices.ExportSurveyDataToCsv(surveyId);
return await _analyticsServices.ExportResponsesToCsv(surveyId);
}
}
}

View File

@@ -1,39 +1,43 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using survey_beta.DTOs.Response;
using survey_beta.Models;
using System;
using System.Threading.Tasks;
namespace survey_beta.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ResponsesController : ControllerBase
public class ResponseController : ControllerBase
{
private readonly ResponsesService _responsesService;
public ResponsesController(ResponsesService responsesService)
public ResponseController(ResponsesService responsesService)
{
_responsesService = responsesService;
}
[HttpPost("add")]
public IActionResult AddResponse([FromBody] ResponseDto request)
public async Task<IActionResult> CreateResponse([FromBody] ResponseDto request)
{
try
{
_responsesService.AddResponse(request);
return Ok("Response added successfully.");
await _responsesService.AddResponseAsync(request);
return Ok(new { message = "Response added successfully." });
}
catch (Exception ex)
{
return BadRequest(new { message = ex.Message });
return BadRequest(new { error = ex.Message });
}
}
[HttpGet("survey/{surveyId}")]
public IActionResult GetSurveyResponses(string surveyId)
public async Task<IActionResult> GetSurveyResponses(string surveyId)
{
var responses = _responsesService.GetSurveyResponses(surveyId);
if (responses == null || responses.Count == 0) return NotFound("No responses found for this survey.");
var responses = await _responsesService.GetSurveyResponsesAsync(surveyId);
if (responses == null || responses.Count == 0)
{
return NotFound(new { message = "No responses found for this survey." });
}
return Ok(responses);
}
}

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNet.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using survey_beta.DTOs.Create;
@@ -14,15 +15,22 @@ using System.Threading.Tasks;
public class SurveyController : ControllerBase
{
private readonly SurveyService _surveyService;
private readonly UserManager<User> _userManager;
private readonly Microsoft.AspNetCore.Identity.UserManager<User> _userManager;
public SurveyController(SurveyService surveyService, UserManager<User> userManager)
public SurveyController(SurveyService surveyService, Microsoft.AspNetCore.Identity.UserManager<User> userManager)
{
_surveyService = surveyService;
_userManager = userManager;
}
[HttpGet("{id}")]
[HttpGet("GetAll")]
public async Task<IActionResult> GetAllSurveys([FromQuery] string id = null)
{
var surveys = await _surveyService.GetAllSurveysAsync(id);
return Ok(surveys);
}
[HttpGet("GetSurveyById{id}")]
public async Task<IActionResult> GetById(string id)
{
var userId = _userManager.GetUserId(User);
@@ -50,23 +58,17 @@ public class SurveyController : ControllerBase
return Ok(result);
}
[HttpPost("Create-Survey")]
// [Authorize]
[HttpPost]
public async Task<ActionResult<Survey>> CreateSurvey([FromBody] CreateSurveyDto request)
public async Task<IActionResult> CreateSurvey([FromBody] CreateSurveyDto request)
{
try
{
var survey = await _surveyService.CreateSurveyAsync(request);
return CreatedAtAction(nameof(GetById), new { id = survey.Id }, survey);
}
catch (Exception ex)
{
return BadRequest(new { message = ex.Message });
}
var userId = _userManager.GetUserId(User);
var survey = await _surveyService.CreateSurveyAsync(request, userId);
return Ok(survey);
}
//[Authorize]
[HttpPut]
[HttpPut("EditSurvey{id}")]
public async Task<IActionResult> UpdateSurvey([FromBody] UpdateSurveyDto request)
{
var success = await _surveyService.UpdateSurveyAsync(request);
@@ -75,7 +77,7 @@ public class SurveyController : ControllerBase
}
//[Authorize]
[HttpPatch("publish/{id}")]
[HttpPatch("publish-Survey/{id}")]
public async Task<IActionResult> PublishSurvey(string id)
{
var success = await _surveyService.PublishSurveyAsync(id);
@@ -84,7 +86,7 @@ public class SurveyController : ControllerBase
}
//[Authorize]
[HttpPatch("unpublish/{id}")]
[HttpPatch("unpublish-Survey/{id}")]
public async Task<IActionResult> UnpublishSurvey(string id)
{
var success = await _surveyService.UnpublishSurveyAsync(id);
@@ -93,7 +95,7 @@ public class SurveyController : ControllerBase
}
//[Authorize]
[HttpDelete("{id}")]
[HttpDelete("Delete-Survey{id}")]
public async Task<IActionResult> DeleteSurvey(string id)
{
var success = await _surveyService.DeleteSurveyAsync(id);

View File

@@ -6,7 +6,7 @@ namespace survey_beta.DTOs.Create
public class CreateQuestionDto
{
public string Content { get; set; }
public string SurveyId { get; set; }
//public string SurveyId { get; set; }
public List<CreateChoiceDto> Choices { get; set; }
}

View File

@@ -9,7 +9,7 @@ namespace survey_beta.DTOs.Create
public string Description { get; set; }
public string Category { get; set; }
public DateTime ExpirationDate { get; set; }
public bool IsPublished { get; set; }
public List<CreateQuestionDto> Questions { get; set; }
}
}

View File

@@ -3,8 +3,7 @@
public class AnswerDto
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Question { get; set; }
public string AnswerText { get; set; }
public string QuestionId { get; set; }
public string ResponseId { get; set; }
}
}

View File

@@ -8,5 +8,6 @@ namespace survey_beta.DTOs.Default
public string Letter { get; set; }
public string Content { get; set; }
public string QuestionId { get; set; }
public bool IsCorrect { get; set; }
}
}

View File

@@ -5,6 +5,8 @@
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Content { get; set; }
public string SurveyId { get; set; }
public List<ChoiceDto> Choices { get; set; }
public string QuestionType { get; set; }
public string QuestionId { get; set; }
public IEnumerable<ChoiceDto> Choices { get; set; }
}
}

View File

@@ -1,12 +1,11 @@
namespace survey_beta.DTOs.Default
{
using survey_beta.DTOs.Default;
public class ResponseDto
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string IpAddress { get; set; }
public string Id { get; set; }
public string SurveyId { get; set; }
public string Answer { get; set; }
public DateTime CreatedAt { get; set; }
}
public string Response { get; set; }
public string ResponseContent { get; set; }
public string? IpAddress { get; set; }
public ICollection<AnswerDto> Answers { get; set; }
}

View File

@@ -2,11 +2,12 @@
{
public class SurveyDto
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public DateTime ExpirationDate { get; set; }
public DateTime CreatedAt { get; set; }
public bool IsPublished { get; set; }
public string AuthorId { get; set; }
public List<QuestionDto> Questions { get; set; }

View File

@@ -1,10 +0,0 @@
namespace survey_beta.DTOs.Response
{
public class ResponseDto
{
public string Id { get; set; }
public string IpAddress { get; set; }
public string SurveyId { get; set; }
public string Response { get; set; }
}
}

View File

@@ -1,10 +1,11 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using survey_beta.Models;
namespace survey_beta.DataBaseContext
{
public class AppDbContext : IdentityDbContext<User>
public class AppDbContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext<User>
{
public DbSet<Survey> Surveys { get; set; }
public DbSet<Question> Questions { get; set; }
@@ -31,10 +32,10 @@ namespace survey_beta.DataBaseContext
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Question>()
.HasOne(q => q.Survey)
.WithMany(s => s.Questions)
.HasForeignKey(q => q.SurveyId)
.OnDelete(DeleteBehavior.Cascade);
.HasIndex(q => q.SurveyId);
modelBuilder.Entity<Choice>()
.HasIndex(c => c.QuestionId);
modelBuilder.Entity<Choice>()
.HasOne(c => c.Question)
@@ -42,12 +43,6 @@ namespace survey_beta.DataBaseContext
.HasForeignKey(c => c.QuestionId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Answer>()
.HasOne(a => a.Response)
.WithMany(r => r.Answers)
.HasForeignKey(a => a.ResponseId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Answer>()
.HasOne(a => a.Question)
.WithMany()

View File

@@ -1,4 +1,5 @@
using survey_beta.DTOs.Create;
#if false
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.Models;
@@ -28,3 +29,4 @@ namespace survey_beta.Mappers
}
}
}
#endif

View File

@@ -0,0 +1,27 @@
using AutoMapper;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.DTOs.Update;
using survey_beta.Models;
namespace survey_beta.Mappers.Profiles
{
public class AnalyticsProfile : Profile
{
public AnalyticsProfile()
{
CreateMap<Response, ResponseDto>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.SurveyId, opt => opt.MapFrom(src => src.SurveyId))
.ForMember(dest => dest.Answers, opt => opt.MapFrom(src => src.Answers));
CreateMap<Answer, AnswerDto>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.QuestionId, opt => opt.MapFrom(src => src.QuestionId));
CreateMap<SurveyAnalytics, SurveyStats>()
.ForMember(dest => dest.SurveyId, opt => opt.MapFrom(src => src.SurveyId))
.ForMember(dest => dest.TotalResponses, opt => opt.MapFrom(src => src.TotalResponses));
}
}
}

View File

@@ -0,0 +1,15 @@
using AutoMapper;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.Models;
namespace survey_beta.Mappers.Profiles
{
public class AnswerProfile : Profile
{
public AnswerProfile()
{
CreateMap<Answer, AnswerDto>();
}
}
}

View File

@@ -0,0 +1,15 @@
using AutoMapper;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.Models;
namespace survey_beta.Mappers.Profiles
{
public class ChoiceProfile : Profile
{
public ChoiceProfile()
{
CreateMap<Choice, ChoiceDto>();
}
}
}

View File

@@ -0,0 +1,22 @@
using AutoMapper;
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.DTOs.Update;
using survey_beta.Models;
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<CreateSurveyDto, Survey>().ForMember(dest => dest.Id, opt => opt.Ignore());
CreateMap<CreateQuestionDto, Question>().ForMember(dest => dest.Id, opt => opt.Ignore());
CreateMap<CreateChoiceDto, Choice>().ForMember(dest => dest.Id, opt => opt.Ignore());
CreateMap<Survey, SurveyDto>();
CreateMap<Question, QuestionDto>();
CreateMap<Choice, ChoiceDto>();
CreateMap<UpdateSurveyDto, Survey>();
}
}

View File

@@ -0,0 +1,15 @@
using AutoMapper;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.Models;
namespace survey_beta.Mappers.Profiles
{
public class QuestionProfile : Profile
{
public QuestionProfile()
{
CreateMap<Question, QuestionDto>();
}
}
}

View File

@@ -0,0 +1,23 @@
namespace survey_beta.Mappers.Profiles
{
using AutoMapper;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.Models;
public class ResponseProfile : Profile
{
public ResponseProfile()
{
CreateMap<ResponseDto, Response>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.SurveyId, opt => opt.MapFrom(src => src.SurveyId))
.ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.Answers, opt => opt.MapFrom(src => src.Answers));
CreateMap<AnswerDto, Answer>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.ResponseId, opt => opt.MapFrom(src => src.ResponseId))
.ForMember(dest => dest.QuestionId, opt => opt.MapFrom(src => src.QuestionId));
}
}
}

View File

@@ -0,0 +1,17 @@
using AutoMapper;
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.Models;
namespace survey_beta.Mappers.Profiles
{
public class SurveyProfile : Profile
{
public SurveyProfile()
{
CreateMap<Survey, SurveyDto>();
CreateMap<CreateSurveyDto, Survey>();
}
}
}

View File

@@ -0,0 +1,16 @@
using AutoMapper;
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.Models;
namespace survey_beta.Mappers.Profiles
{
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<User, UserDto>();
CreateMap<CreateUserDto, User>();
}
}
}

View File

@@ -1,4 +1,6 @@
using survey_beta.DTOs.Create;
#if false
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.Models;
@@ -22,8 +24,9 @@ namespace survey_beta.Mappers
{
Id = Guid.NewGuid().ToString(),
Content = dto.Content,
SurveyId = dto.SurveyId
// SurveyId = dto.SurveyId
};
}
}
}
#endif

View File

@@ -1,4 +1,5 @@
using survey_beta.DTOs.Create;
#if false
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.Models;
@@ -27,3 +28,4 @@ namespace survey_beta.Mappers
}
}
}
#endif

View File

@@ -1,4 +1,5 @@
using survey_beta.DTOs.Create;
#if false
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.Models;
@@ -34,3 +35,4 @@ namespace survey_beta.Mappers
}
}
}
#endif

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Identity;
#if false
using Microsoft.AspNetCore.Identity;
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.Models;
@@ -33,3 +34,4 @@ namespace survey_beta.Mappers
}
}
}
#endif

View File

@@ -0,0 +1,485 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using survey_beta.DataBaseContext;
#nullable disable
namespace survey_beta.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20250204184529_answer")]
partial class answer
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.1")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("survey_beta.Models.Answer", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ChoiceId")
.HasColumnType("text");
b.Property<string>("QuestionId")
.HasColumnType("text");
b.Property<string>("ResponseId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ChoiceId");
b.HasIndex("QuestionId");
b.HasIndex("ResponseId");
b.ToTable("Answers");
});
modelBuilder.Entity("survey_beta.Models.Choice", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("Letter")
.HasColumnType("text");
b.Property<string>("QuestionId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.ToTable("Choices");
});
modelBuilder.Entity("survey_beta.Models.Question", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("SurveyId")
.HasColumnType("text");
b.Property<string>("Text")
.HasColumnType("text");
b.Property<string>("Type")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SurveyId");
b.ToTable("Questions");
});
modelBuilder.Entity("survey_beta.Models.Response", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("SurveyId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SurveyId");
b.ToTable("Responses");
});
modelBuilder.Entity("survey_beta.Models.Survey", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("AuthorId")
.HasColumnType("text");
b.Property<string>("Category")
.HasColumnType("text");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<DateTime?>("ExpirationDate")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsPublished")
.HasColumnType("boolean");
b.Property<string>("Title")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("AuthorId");
b.ToTable("Surveys");
});
modelBuilder.Entity("survey_beta.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("Fullname")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("survey_beta.Models.Answer", b =>
{
b.HasOne("survey_beta.Models.Choice", "Choice")
.WithMany()
.HasForeignKey("ChoiceId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("survey_beta.Models.Question", "Question")
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("survey_beta.Models.Response", "Response")
.WithMany("Answers")
.HasForeignKey("ResponseId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Choice");
b.Navigation("Question");
b.Navigation("Response");
});
modelBuilder.Entity("survey_beta.Models.Choice", b =>
{
b.HasOne("survey_beta.Models.Question", "Question")
.WithMany("Choices")
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Question");
});
modelBuilder.Entity("survey_beta.Models.Question", b =>
{
b.HasOne("survey_beta.Models.Survey", "Survey")
.WithMany("Questions")
.HasForeignKey("SurveyId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Survey");
});
modelBuilder.Entity("survey_beta.Models.Response", b =>
{
b.HasOne("survey_beta.Models.Survey", "Survey")
.WithMany()
.HasForeignKey("SurveyId");
b.Navigation("Survey");
});
modelBuilder.Entity("survey_beta.Models.Survey", b =>
{
b.HasOne("survey_beta.Models.User", "Author")
.WithMany("Surveys")
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Author");
});
modelBuilder.Entity("survey_beta.Models.Question", b =>
{
b.Navigation("Choices");
});
modelBuilder.Entity("survey_beta.Models.Response", b =>
{
b.Navigation("Answers");
});
modelBuilder.Entity("survey_beta.Models.Survey", b =>
{
b.Navigation("Questions");
});
modelBuilder.Entity("survey_beta.Models.User", b =>
{
b.Navigation("Surveys");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,123 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace survey_beta.Migrations
{
/// <inheritdoc />
public partial class answer : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses");
migrationBuilder.AlterColumn<string>(
name: "SurveyId",
table: "Responses",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddColumn<string>(
name: "IpAddress",
table: "Responses",
type: "text",
nullable: true);
migrationBuilder.AlterColumn<string>(
name: "ResponseId",
table: "Answers",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "QuestionId",
table: "Answers",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "ChoiceId",
table: "Answers",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses",
column: "SurveyId",
principalTable: "Surveys",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses");
migrationBuilder.DropColumn(
name: "IpAddress",
table: "Responses");
migrationBuilder.AlterColumn<string>(
name: "SurveyId",
table: "Responses",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ResponseId",
table: "Answers",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "QuestionId",
table: "Answers",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ChoiceId",
table: "Answers",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses",
column: "SurveyId",
principalTable: "Surveys",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@@ -0,0 +1,487 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using survey_beta.DataBaseContext;
#nullable disable
namespace survey_beta.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20250205124722_Choice")]
partial class Choice
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.1")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("survey_beta.Models.Answer", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ChoiceId")
.HasColumnType("text");
b.Property<string>("QuestionId")
.HasColumnType("text");
b.Property<string>("ResponseId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ChoiceId");
b.HasIndex("QuestionId");
b.HasIndex("ResponseId");
b.ToTable("Answers");
});
modelBuilder.Entity("survey_beta.Models.Choice", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("Letter")
.HasColumnType("text");
b.Property<string>("QuestionId")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("QuestionId");
b.ToTable("Choices");
});
modelBuilder.Entity("survey_beta.Models.Question", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Content")
.HasColumnType("text");
b.Property<string>("SurveyId")
.HasColumnType("text");
b.Property<string>("Text")
.HasColumnType("text");
b.Property<string>("Type")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SurveyId");
b.ToTable("Questions");
});
modelBuilder.Entity("survey_beta.Models.Response", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("SurveyId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SurveyId");
b.ToTable("Responses");
});
modelBuilder.Entity("survey_beta.Models.Survey", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("AuthorId")
.HasColumnType("text");
b.Property<string>("Category")
.HasColumnType("text");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<DateTime?>("ExpirationDate")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsPublished")
.HasColumnType("boolean");
b.Property<string>("Title")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("AuthorId");
b.ToTable("Surveys");
});
modelBuilder.Entity("survey_beta.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("Fullname")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("survey_beta.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("survey_beta.Models.Answer", b =>
{
b.HasOne("survey_beta.Models.Choice", "Choice")
.WithMany()
.HasForeignKey("ChoiceId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("survey_beta.Models.Question", "Question")
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("survey_beta.Models.Response", "Response")
.WithMany("Answers")
.HasForeignKey("ResponseId");
b.Navigation("Choice");
b.Navigation("Question");
b.Navigation("Response");
});
modelBuilder.Entity("survey_beta.Models.Choice", b =>
{
b.HasOne("survey_beta.Models.Question", "Question")
.WithMany("Choices")
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Question");
});
modelBuilder.Entity("survey_beta.Models.Question", b =>
{
b.HasOne("survey_beta.Models.Survey", "Survey")
.WithMany("Questions")
.HasForeignKey("SurveyId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Survey");
});
modelBuilder.Entity("survey_beta.Models.Response", b =>
{
b.HasOne("survey_beta.Models.Survey", "Survey")
.WithMany()
.HasForeignKey("SurveyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Survey");
});
modelBuilder.Entity("survey_beta.Models.Survey", b =>
{
b.HasOne("survey_beta.Models.User", "Author")
.WithMany("Surveys")
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Author");
});
modelBuilder.Entity("survey_beta.Models.Question", b =>
{
b.Navigation("Choices");
});
modelBuilder.Entity("survey_beta.Models.Response", b =>
{
b.Navigation("Answers");
});
modelBuilder.Entity("survey_beta.Models.Survey", b =>
{
b.Navigation("Questions");
});
modelBuilder.Entity("survey_beta.Models.User", b =>
{
b.Navigation("Surveys");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,82 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace survey_beta.Migrations
{
/// <inheritdoc />
public partial class Choice : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Answers_Responses_ResponseId",
table: "Answers");
migrationBuilder.DropForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses");
migrationBuilder.AlterColumn<string>(
name: "SurveyId",
table: "Responses",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Answers_Responses_ResponseId",
table: "Answers",
column: "ResponseId",
principalTable: "Responses",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses",
column: "SurveyId",
principalTable: "Surveys",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Answers_Responses_ResponseId",
table: "Answers");
migrationBuilder.DropForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses");
migrationBuilder.AlterColumn<string>(
name: "SurveyId",
table: "Responses",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddForeignKey(
name: "FK_Answers_Responses_ResponseId",
table: "Answers",
column: "ResponseId",
principalTable: "Responses",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Responses_Surveys_SurveyId",
table: "Responses",
column: "SurveyId",
principalTable: "Surveys",
principalColumn: "Id");
}
}
}

View File

@@ -160,15 +160,12 @@ namespace survey_beta.Migrations
.HasColumnType("text");
b.Property<string>("ChoiceId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("QuestionId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ResponseId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
@@ -235,6 +232,9 @@ namespace survey_beta.Migrations
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("SurveyId")
.IsRequired()
.HasColumnType("text");
@@ -400,20 +400,16 @@ namespace survey_beta.Migrations
b.HasOne("survey_beta.Models.Choice", "Choice")
.WithMany()
.HasForeignKey("ChoiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("survey_beta.Models.Question", "Question")
.WithMany()
.HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("survey_beta.Models.Response", "Response")
.WithMany("Answers")
.HasForeignKey("ResponseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("ResponseId");
b.Navigation("Choice");

View File

@@ -6,8 +6,8 @@ namespace survey_beta.Models
public class Response
{
public string Id { get; set; } = Guid.NewGuid().ToString();
//public string IpAddress { get; set; }
public string? SurveyId { get; set; }
public string? IpAddress { get; set; }
public string SurveyId { get; set; }
public Survey? Survey { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public ICollection<Answer> Answers { get; set; } = new List<Answer>();

View File

@@ -3,13 +3,14 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using survey_beta.DataBaseContext;
using survey_beta.Mappers.Profiles;
using survey_beta.Models;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
@@ -65,7 +66,14 @@ builder.Services.AddScoped<UsersServices>();
builder.Services.AddScoped<SurveyService>();
builder.Services.AddScoped<ResponsesService>();
builder.Services.AddScoped<AnalyticsServices>();
builder.Services.AddAutoMapper(typeof(MappingProfile));
builder.Services.AddAutoMapper(typeof(UserProfile));
builder.Services.AddAutoMapper(typeof(ResponseProfile));
builder.Services.AddAutoMapper(typeof(AnalyticsProfile));
builder.Services.AddAutoMapper(typeof(AnswerProfile));
builder.Services.AddAutoMapper(typeof(ChoiceProfile));
builder.Services.AddAutoMapper(typeof(QuestionProfile));
builder.Services.AddAutoMapper(typeof(SurveyProfile));
var app = builder.Build();
// HTTP request pipeline

View File

@@ -1,21 +1,27 @@
using Microsoft.AspNetCore.Http.HttpResults;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using survey_beta.DataBaseContext;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Update;
using survey_beta.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
public class AnalyticsServices
{
private readonly AppDbContext _context;
public AnalyticsServices(AppDbContext context)
private readonly IMapper _mapper;
public AnalyticsServices(AppDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public void UpdateAnalytics(string surveyId)
{
var responses = _context.Responses
@@ -28,6 +34,7 @@ public class AnalyticsServices
SaveAnalytics(surveyId, analyticsData);
}
private SurveyStats CalculateAnalytics(List<Response> responses)
{
var answerFrequency = new Dictionary<string, int>();
@@ -38,24 +45,21 @@ public class AnalyticsServices
foreach (var answer in response.Answers)
{
var choiceText = answer.Choice?.Letter;
if (choiceText != null)
if (!string.IsNullOrEmpty(choiceText))
{
if (answerFrequency.ContainsKey(choiceText))
{
answerFrequency[choiceText]++;
}
else
{
answerFrequency[choiceText] = 1;
}
}
if (questionFrequency.ContainsKey(answer.Question?.Text))
var questionText = answer.Question?.Text;
if (!string.IsNullOrEmpty(questionText))
{
questionFrequency[answer.Question.Text]++;
}
if (questionFrequency.ContainsKey(questionText))
questionFrequency[questionText]++;
else
{
questionFrequency[answer.Question.Text] = 1;
questionFrequency[questionText] = 1;
}
}
}
@@ -68,18 +72,17 @@ public class AnalyticsServices
QuestionFrequency = questionFrequency
};
}
private void SaveAnalytics(string surveyId, SurveyStats analyticsData)
{
var analytics = new SurveyAnalytics
{
SurveyId = surveyId,
TotalResponses = analyticsData.TotalResponses,
CreatedAt = DateTime.UtcNow,
};
var analytics = _mapper.Map<SurveyAnalytics>(analyticsData);
analytics.SurveyId = surveyId;
analytics.CreatedAt = DateTime.UtcNow;
_context.Add(analytics);
_context.SaveChanges();
}
public SurveyStats GetAggregatedSurveyResponses(string surveyId)
{
var responses = _context.Responses
@@ -90,37 +93,34 @@ public class AnalyticsServices
return CalculateAnalytics(responses);
}
public IActionResult ExportSurveyDataToCsv(string surveyId)
public async Task<IActionResult> ExportResponsesToCsv(string surveyId)
{
var responses = _context.Responses
var responses = await _context.Responses
.Where(r => r.SurveyId == surveyId)
.Include(r => r.Answers)
.ThenInclude(a => a.Question)
.Include(r => r.Answers)
.ThenInclude(a => a.Choice)
.ToList();
if (responses == null || responses.Count == 0)
{
return new ObjectResult("No responses found for this survey.")
{
StatusCode = 404
};
}
.ToListAsync();
var csvData = new StringWriter();
var csvHeader = "ResponseId,Question,ChoiceText";
csvData.WriteLine(csvHeader);
var csvLines = new List<string>
{
"ResponseId,Question,ChoiceText"
};
foreach (var response in responses)
{
foreach (var answer in response.Answers)
{
var choiceText = answer.Choice?.Letter ?? "No Choice";
var csvLine = $"{response.Id},{answer.Question?.Text},{choiceText}";
csvData.WriteLine(csvLine);
var questionText = answer.Question.Content;
csvLines.Add($"{response.Id},{questionText}");
}
}
var fileName = $"{surveyId}_responses.csv";
var fileBytes = System.Text.Encoding.UTF8.GetBytes(csvData.ToString());
var fileName = "Survey_Responses.csv";
var fileBytes = Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, csvLines));
return new FileContentResult(fileBytes, "text/csv")
{
FileDownloadName = fileName

View File

@@ -1,44 +1,51 @@
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using survey_beta.DataBaseContext;
using survey_beta.DTOs.Response;
using survey_beta.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class ResponsesService
{
private readonly AppDbContext _context;
private readonly AnalyticsServices _analyticsService;
private readonly IMapper _mapper;
public ResponsesService(AppDbContext context, AnalyticsServices analyticsService)
public ResponsesService(AppDbContext context, IMapper mapper)
{
_context = context;
_analyticsService = analyticsService;
_mapper = mapper;
}
public void AddResponse(ResponseDto request)
public async Task AddResponseAsync(ResponseDto responseDto)
{
var response = new Response
{
SurveyId = request.SurveyId,
Id = request.Id,
Id = responseDto.Id,
SurveyId = responseDto.SurveyId,
IpAddress = responseDto.IpAddress,
CreatedAt = DateTime.UtcNow,
// CreatedAt = DateTime.UtcNow,
//IpAddress= request.IpAddress
//Answers = request.Answers.Select(a => new Answer
//{
// }).ToList()
};
_context.Responses.Add(response);
_context.SaveChanges();
foreach (var answer in responseDto.Answers)
{
var answerEntity = new Answer
{
QuestionId = answer.QuestionId,
ResponseId = response.Id
};
response.Answers.Add(answerEntity);
}
public List<Response> GetSurveyResponses(string surveyId)
await _context.Responses.AddAsync(response);
await _context.SaveChangesAsync();
}
public async Task<List<Response>> GetSurveyResponsesAsync(string surveyId)
{
return _context.Responses
return await _context.Responses
.Where(r => r.SurveyId == surveyId)
.Include(r => r.Answers)
.ToList();
.ToListAsync();
}
}

View File

@@ -1,72 +1,71 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using survey_beta.DataBaseContext;
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
using survey_beta.DTOs.Response;
using survey_beta.DTOs.Update;
using survey_beta.DTOs.Response;
using survey_beta.Models;
using System.Security.Claims;
using AutoMapper;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System;
using survey_beta.DTOs.Default;
public class SurveyService
{
private readonly AppDbContext _context;
private readonly IMapper _mapper;
private readonly ResponsesService _responsesService;
public SurveyService(AppDbContext context, ResponsesService responsesService)
public SurveyService(AppDbContext context, IMapper mapper, ResponsesService responsesService)
{
_context = context;
_mapper = mapper;
_responsesService = responsesService;
}
public async Task<List<SurveyDto>> GetAllSurveysAsync(string id = null)
{
IQueryable<Survey> query = _context.Surveys.Include(s => s.Questions);
public async Task<Survey> GetSurveyByIdAsync(string id)
if (!string.IsNullOrEmpty(id))
{
return await _context.Surveys
query = query.Where(s => s.Id == id);
}
var surveys = await query.ToListAsync();
return _mapper.Map<List<SurveyDto>>(surveys);
}
public async Task<SurveyDto> GetSurveyByIdAsync(string id)
{
var survey = await _context.Surveys.AsNoTracking()
.Include(s => s.Questions)
.ThenInclude(q => q.Choices)
.FirstOrDefaultAsync(s => s.Id == id);
return survey == null ? null : _mapper.Map<SurveyDto>(survey);
}
public async Task<List<Survey>> GetUserSurveysAsync(string userId)
public async Task<SurveyDto> CreateSurveyAsync(CreateSurveyDto request, string userId)
{
return await _context.Surveys.Where(s => s.AuthorId == userId).ToListAsync();
}
public async Task<Survey> CreateSurveyAsync(CreateSurveyDto request)
{
var survey = new Survey
{
Id = Guid.NewGuid().ToString(),
Title = request.Title,
Description = request.Description,
Category = request.Category,
ExpirationDate = request.ExpirationDate,
AuthorId = null,
Questions = request.Questions.Select(q => new Question
{
Id = Guid.NewGuid().ToString(),
Text = q.Content,
}).ToList()
};
var survey = _mapper.Map<Survey>(request);
survey.Id = Guid.NewGuid().ToString();
survey.AuthorId = userId;
_context.Surveys.Add(survey);
await _context.SaveChangesAsync();
return survey;
return _mapper.Map<SurveyDto>(survey);
}
public async Task<bool> UpdateSurveyAsync(UpdateSurveyDto request)
{
var survey = await _context.Surveys.FindAsync(request.Id);
if (survey == null) return false;
survey.Title = request.Title;
survey.Description = request.Description;
survey.Category = request.Category;
survey.ExpirationDate = request.ExpirationDate;
survey.IsPublished = request.IsPublished;
_mapper.Map(request, survey);
await _context.SaveChangesAsync();
return true;
}
public async Task<bool> PublishSurveyAsync(string id)
{
var survey = await _context.Surveys.FindAsync(id);
@@ -76,6 +75,7 @@ public class SurveyService
await _context.SaveChangesAsync();
return true;
}
public async Task<bool> UnpublishSurveyAsync(string id)
{
var survey = await _context.Surveys.FindAsync(id);
@@ -85,27 +85,18 @@ public class SurveyService
await _context.SaveChangesAsync();
return true;
}
public async Task<bool> DeleteSurveyAsync(string id)
{
var survey = await _context.Surveys.FindAsync(id);
var survey = await _context.Surveys.AsNoTracking()
.Include(s => s.Questions)
.ThenInclude(q => q.Choices)
.FirstOrDefaultAsync(s => s.Id == id);
if (survey == null) return false;
_context.Surveys.Remove(survey);
await _context.SaveChangesAsync();
return true;
}
public async Task<bool> SubmitSurveyResponseAsync(string surveyId, survey_beta.DTOs.Response.ResponseDto responseDto)
{
var survey = await _context.Surveys
.Include(s => s.Questions)
.FirstOrDefaultAsync(s => s.Id == surveyId);
if (survey == null)
{
return false;
}
_responsesService.AddResponse(responseDto);
return true;
}
}

View File

@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using survey_beta.DTOs.Create;
using survey_beta.DTOs.Default;
@@ -7,19 +6,23 @@ using survey_beta.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using AutoMapper;
public class UsersServices
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;
private readonly IConfiguration _configuration;
private readonly IMapper _mapper;
public UsersServices(UserManager<User> userManager, SignInManager<User> signInManager, IConfiguration configuration)
public UsersServices(UserManager<User> userManager, SignInManager<User> signInManager, IConfiguration configuration, IMapper mapper)
{
_userManager = userManager;
_signInManager = signInManager;
_configuration = configuration;
_mapper = mapper;
}
public async Task<UserDto> CreateUserAsync(CreateUserDto createUserDto)
{
var existingUser = await _userManager.FindByEmailAsync(createUserDto.Email);
@@ -28,12 +31,7 @@ public class UsersServices
throw new Exception("User with this email already exists.");
}
var user = new User
{
UserName = createUserDto.Username,
Email = createUserDto.Email,
Fullname = createUserDto.Fullname
};
var user = _mapper.Map<User>(createUserDto);
var result = await _userManager.CreateAsync(user, createUserDto.Password);
if (!result.Succeeded)
@@ -41,14 +39,10 @@ public class UsersServices
throw new Exception("Failed to create user: " + string.Join(", ", result.Errors.Select(e => e.Description)));
}
return new UserDto
{
Id = user.Id,
Email = user.Email,
Username = user.UserName,
Fullname = user.Fullname,
Token = GenerateJwtToken(user)
};
var userDto = _mapper.Map<UserDto>(user);
userDto.Token = GenerateJwtToken(user);
return userDto;
}
public async Task<UserDto> SignInAsync(LoginDto loginDto)
{
@@ -64,14 +58,10 @@ public class UsersServices
throw new Exception("Invalid login attempt.");
}
return new UserDto
{
Id = user.Id,
Email = user.Email,
Username = user.UserName,
Fullname = user.Fullname,
Token = GenerateJwtToken(user)
};
var userDto = _mapper.Map<UserDto>(user);
userDto.Token = GenerateJwtToken(user);
return userDto;
}
public async Task<UserDto> GetUserByIdAsync(string userId)
{
@@ -81,13 +71,7 @@ public class UsersServices
throw new Exception("User not found.");
}
return new UserDto
{
Id = user.Id,
Email = user.Email,
Username = user.UserName,
Fullname = user.Fullname
};
return _mapper.Map<UserDto>(user);
}
public async Task<UserDto> GetUserByUsernameAsync(string username)
{
@@ -97,13 +81,7 @@ public class UsersServices
throw new Exception("User not found.");
}
return new UserDto
{
Id = user.Id,
Email = user.Email,
Username = user.UserName,
Fullname = user.Fullname
};
return _mapper.Map<UserDto>(user);
}
private string GenerateJwtToken(User user)
{
@@ -127,26 +105,18 @@ public class UsersServices
return new JwtSecurityTokenHandler().WriteToken(token);
}
public async Task<List<UserDto>> GetAllUsersAsync()
{
var users = _userManager.Users.ToList();
var userDtos = users.Select(user => new UserDto
{
Id = user.Id,
Email = user.Email,
Username = user.UserName,
Fullname = user.Fullname
}).ToList();
return userDtos;
return _mapper.Map<List<UserDto>>(users);
}
public async Task<bool> DeleteUsersAsync(string userid)
{
var user = await _userManager.FindByIdAsync(userid);
if (user == null) return false;
var result = await _userManager.DeleteAsync(user);
if (!result.Succeeded) return false;
return true;
return result.Succeeded;
}
}

View File

@@ -6,6 +6,6 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=SurveyBeta;Username=postgres;Password=102030"
"DefaultConnection": "Host=localhost;Database=SurveyBeta;Username=postgres;Password=MAJEDali645"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More