Display only the current user logged in records in the index view in ASP.NET Core MVC?

43 Views Asked by At

How can I display the currently logged in user's records in the index view? I don't want them to see other users record, I just want them to see their own added records in the database. I already have implemented identity authentication and verification so users can have their own accounts. Please help me modify my code. I can't see any resources about this problem. I do not have ApplicationUser so I used IdentityUser instead.

This is currently my class model:

 public class CommitmentForm
 {
    [Key]
    public int CommitmentId { get; set; }

    [Required]
    public string? OrganizationName { get; set; }

    [Required]
    public string? AdvicerName { get; set; }

    [Required]
    public string? HomeAddress { get; set; }

    [Required]
    public string? ContactNo { get; set; }

    public int CollegeId { get; set; }
    [ForeignKey("CollegeId")]
    [ValidateNever]
    public College College { get; set; }

    public int AcademicRankId { get; set; }
    [ForeignKey("AcademicRankId")]
    [ValidateNever]
    public AcademicRank AcademicRank { get; set; }

    [Display(Name = "School Year")]
    public int SchoolYear { get; set; } = DateTime.Now.Year;
 }

This is currently my View Model:

public class CommitmentFormVM
{
    public CommitmentForm CommitmentForm { get; set; }

    [ValidateNever]
    public IEnumerable<SelectListItem> CollegeList { get; set; }
    [ValidateNever]
    public IEnumerable<SelectListItem> AcademicRankList { get; set; }
}

This is my Controller Actions:

public class CommitmentFormController : Controller
{
    private readonly ApplicationDbContext _db;
    private readonly IUnitOfWork _unitOfWork;
    private readonly UserManager<IdentityUser> _userManager;

    public CommitmentFormController(ApplicationDbContext db, IUnitOfWork unitOfWork, UserManager<IdentityUser> userManager)
    {
        _db = db;
        _unitOfWork = unitOfWork;
        _userManager = userManager;
    }

    //public IActionResult Index()
    //{
    //    string userId = Commonism.getUserId(this.User);

    //    var User = _db.Users.SingleOrDefault(m => m.Id == userId);

    //    if (User == null)
    //    {
    //        return NotFound();
    //    }

    //    var currentUserCommitments = _db.CommitmentForms.Where(u => u.UserId == userId).ToList();

    //    return View(currentUserCommitments);
    //}

    [HttpGet]
    public IActionResult Details(int? id)
    {
        if (id == null || _unitOfWork.Commitment == null)
        {
            return NotFound();
        }

        var commitmentObj = _unitOfWork.Commitment.Get(u => u.CommitmentId == id, includeProperties: "College,AcademicRank");

        if (commitmentObj == null)
        {
            return NotFound();
        }

        return View(commitmentObj);
    }

    [HttpGet]
    public async Task<IActionResult> Upsert(int? id)
    {
        CommitmentFormVM cmVM = new CommitmentFormVM
        {
            CollegeList = _unitOfWork.College.
            GetAll().Select(u => new SelectListItem
            {
                Text = u.CollegeName,
                Value = u.CollegeId.ToString()
            }),

            AcademicRankList = _unitOfWork.AcademicRank.
            GetAll().Select(u => new SelectListItem
            {
                Text = u.RankName,
                Value = u.AcademicRankId.ToString()
            }),

            CommitmentForm = new CommitmentForm()
        };

        if (id == null || id == 0)
        {
            // create
            return View(cmVM);
        }
        else
        {
            // update
            cmVM.CommitmentForm = _unitOfWork.Commitment.Get(u => u.CommitmentId == id);
            return View(cmVM);
        }
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Upsert(CommitmentFormVM commitmentFormVM)
    {
        if (ModelState.IsValid)
        {
            if (commitmentFormVM.CommitmentForm.CommitmentId == 0)
            {
                _unitOfWork.Commitment.Add(commitmentFormVM.CommitmentForm);
                TempData["success"] = "Commitment Form added successfully";
            }
            else
            {
                _unitOfWork.Commitment.Update(commitmentFormVM.CommitmentForm);
                TempData["success"] = "Commitment Form updated successfully";
            }
            _unitOfWork.SaveChanges();
            return RedirectToAction("Details", new { id = commitmentFormVM.CommitmentForm.CommitmentId });
        }
        else
        {
            commitmentFormVM.CollegeList = _unitOfWork.College.
            GetAll().Select(u => new SelectListItem
            {
                Text = u.CollegeName,
                Value = u.CollegeId.ToString()
            });
            commitmentFormVM.AcademicRankList = _unitOfWork.AcademicRank.
            GetAll().Select(u => new SelectListItem
            {
                Text = u.RankName,
                Value = u.AcademicRankId.ToString()
            });

            return View(commitmentFormVM);
        }         
    }

    public IActionResult Delete(int? id)
    {
        CommitmentFormVM cmVM = new()
        {
            CollegeList = _unitOfWork.College.
            GetAll().Select(u => new SelectListItem
            {
                Text = u.CollegeName,
                Value = u.CollegeId.ToString()
            }),
            AcademicRankList = _unitOfWork.AcademicRank.
            GetAll().Select(u => new SelectListItem
            {
                Text = u.RankName,
                Value = u.AcademicRankId.ToString()
            }),
            CommitmentForm = new CommitmentForm(),
        };

        // delete
        cmVM.CommitmentForm = _unitOfWork.Commitment.Get(u => u.CommitmentId == id);
        return View(cmVM);
        
    }

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public IActionResult DeleteCategory(int? id)
    {
        if (_unitOfWork == null)
        {
            return Problem("Entity set 'IUnitOfWork'  is null.");
        }
        CommitmentForm? category = _unitOfWork.Commitment.Get(u => u.CommitmentId == id);
        if (category != null)
        {
            _unitOfWork.Commitment.Remove(category);
        }

        _unitOfWork.SaveChanges();
        TempData["success"] = "Commitment Form deleted successfully"; //for toaster before redirecting
        return RedirectToAction("Index", "Home");
    }

}

I commented the Index Action cause I don't know what to do.

Here is my Upsert view if ever I need to change something in there:

@model CommitmentFormVM;

<div class="college-create-container" style="margin-top:10rem">

    <div class="cf-form-container">

        <div class="cf-logo-container">
            @(Model.CommitmentForm.CommitmentId != 0 ? "Update" : "Create") Commitment Form
        </div>

        <form method="post" class="cf-form">
            <input asp-for="CommitmentForm.CommitmentId" hidden />

            <div class="cf-form-group">
                <label for="orgName">Organization Name</label>
                <input asp-for="CommitmentForm.OrganizationName" type="text" id="orgName" placeholder="College Name">
                <span asp-validation-for="CommitmentForm.OrganizationName" class="text-danger"></span>
            </div>

            <div class="cf-form-group">
                <label for="advName">Advicer Name</label>
                <input asp-for="CommitmentForm.AdvicerName" type="text" id="advName" placeholder="College Name">
                <span asp-validation-for="CommitmentForm.AdvicerName" class="text-danger"></span>
            </div>

            <div class="cf-form-group">
                <label for="address">Home Address</label>
                <input asp-for="CommitmentForm.HomeAddress" type="text" id="address" placeholder="College Name">
                <span asp-validation-for="CommitmentForm.HomeAddress" class="text-danger"></span>
            </div>

            <div class="cf-form-group">
                <label for="cn">Contact Number</label>
                <input asp-for="CommitmentForm.ContactNo" type="text" id="cn" placeholder="College Name">
                <span asp-validation-for="CommitmentForm.ContactNo" class="text-danger"></span>
            </div>

            <div class="cf-form-group">
                <label for="sy">School Year</label>
                <input asp-for="CommitmentForm.SchoolYear" type="text" id="sy" disabled>
                <span asp-validation-for="CommitmentForm.SchoolYear" class="text-danger"></span>
            </div>

            <div class="cf-row">
                <div class="cf-form-group">
                    <label for="college">College</label>
                    <select asp-for="@Model.CommitmentForm.CollegeId" asp-items="@Model.CollegeList" id="college" class="form-select">
                        <option disabled selected>--Select College--</option>
                    </select>
                    <span asp-validation-for="CommitmentForm.CollegeId" class="text-danger"></span>
                </div>

                <div class="cf-form-group">
                    <label for="ar">Academic Rank</label>
                    <select asp-for="@Model.CommitmentForm.AcademicRankId" asp-items="@Model.AcademicRankList" id="ar" class="form-select">
                        <option disabled selected>--Select Academic Rank--</option>
                    </select>
                    <span asp-validation-for="CommitmentForm.AcademicRankId" class="text-danger"></span>
                </div>
            </div>

            @if(Model.CommitmentForm.CommitmentId != 0)
            {
                <button class="cf-form-submit-btn" type="submit">Update</button>
            }
            else
            {
                <button class="cf-form-submit-btn" type="submit">Submit</button>
            }
        </form>

    </div>

</div>

(I already get the current logged in user ID and displayed in in a form. It is visible before i click the submit button, but after that, the userId disappears which led to modelstate.isValid to be false and not proceed to the index view) The code above in upsert httppost direct to details action because I don't still have a view for index, but what I want is to navigate them to the index first after creating a record and there they can see their own created records.

(I expect that once a user created a record, they will be navigated to index view where the list of their own created records are shown. They should not see other users records)

2

There are 2 best solutions below

0
Brando Zhang On

Firstly , you should make sure there is the relation ship between the CommitmentForm and the ApplicationUser(custom identity user) which makes the one to one or one to many for them.

Like below:

public class CommitmentForm { [Key] public int CommitmentId { get; set; }

[Required]
public string? OrganizationName { get; set; }

[Required]
public string? AdvicerName { get; set; }

[Required]
public string? HomeAddress { get; set; }

[Required]
public string? ContactNo { get; set; }

public int CollegeId { get; set; }
[ForeignKey("CollegeId")]
[ValidateNever]
public College College { get; set; }

public int AcademicRankId { get; set; }
[ForeignKey("AcademicRankId")]
[ValidateNever]
public AcademicRank AcademicRank { get; set; }

[Display(Name = "School Year")]
public int SchoolYear { get; set; } = DateTime.Now.Year;

public ApplicationUser IdentityUser { get; set; }

}

Then you could create a custom identity user like below:

Create a new class:

  public class ApplicationUser : IdentityUser
  {
      public CommitmentForm CommitmentForm { get; set; }
  }

Modify the dbcontext:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
     public DbSet<CommitmentForm> CommitmentForms { get; set; }
}

Then modify the program.cs:

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

Then we have the relationship for this two class.

Then inside the view, you could query the ID to the index view, like below:

    private readonly ILogger<HomeController> _logger;

    private readonly ApplicationDbContext _db;
 


    public HomeController(ILogger<HomeController> logger, ApplicationDbContext db)
    {
        _logger = logger;
        _db = db;
     
    }

    public IActionResult Index()
    {
        var currentUserCommitments = new List<CommitmentForm>();
        if (User.Identity.IsAuthenticated)
        {
           currentUserCommitments = _db.CommitmentForms.Where(u => u.IdentityUser.UserName ==  User.Identity

.Name).ToList(); }

        return View(currentUserCommitments);
    }

Then for the model validate failed issue, you need use debug tool to debug which property caused the model fail, and if some fired is required inside the CommitmentFormVM, like application user Id, you could create a hidden field to store it.

<input type="hidden" asp-for="CommitmentForm.IdentityUser.Id"/>
0
Aardvark On

You might also want to look at row-level security in the database. Even reading the database documentation may give you a better idea on how to implement this in .Net.