ASP.NET MVC limit Table view depending on user role - asp.net-mvc

So I'm building a web app for tracking holidays across a company that has different sites. I need to display list of employees on my admin page but I only want Managers/Admins to view the employee list related to them based on their sites (they may have one or many).
On my Admin page, I have created a table of employees from my database, which displays all employees and links to their details on each row.
Controller :
public ActionResult Index(int? page, string searchString)
{
var employees = db.Employees.Include(e => e.Area).Include(e => e.Discipline).Include(e => e.Shift).Include(e => e.Site).Include(e => e.UserRole);
return View(employees.ToList().ToPagedList(page ?? 1, 10 ));
}
Model:
public partial class Employee
public Employee()
{
this.HolidayRequestForms = new HashSet<HolidayRequestForm>();
}
public int EmployeeID { get; set; }
public string FullName { get; set; }
[Required(ErrorMessage = "This Field is Required")]
public string EmailID { get; set; }
[Required(ErrorMessage = "This Field is Required")]
public string Password { get; set; }
public System.DateTime StartDate { get; set; }
public int RoleID { get; set; }
public int ShiftID { get; set; }
public int AreaID { get; set; }
public int DisciplineID { get; set; }
public int SiteID { get; set; }
public int ALCategory { get; set; }
public Nullable<int> HoursTaken { get; set; }
public Nullable<int> AwardedLeave { get; set; }
public Nullable<int> TotalHoursThisYear { get; set; }
public int HoursCarriedForward { get; set; }
public Nullable<int> EntitlementRemainingThisYear { get; set; }
public string Comments { get; set; }
public int SickLeaveTaken { get; set; }
public Nullable<int> SickLeaveEntitlement { get; set; }
public Nullable<int> SickLeaveEntitlementRemaining { get; set; }
public int StudyLeaveEntitlement { get; set; }
public int StudyLeaveTaken { get; set; }
public Nullable<int> StudyLeaveRemaining { get; set; }
public int ExamLeaveTaken { get; set; }
public int ForceMajeure { get; set; }
public int BereavementLeaveTaken { get; set; }
public int MaternityLeaveTaken { get; set; }
public int ParentalLeaveTaken { get; set; }
public int AdoptionLeaveTaken { get; set; }
public string LoginErrorMessage { get; set; }
public virtual Area Area { get; set; }
public virtual Discipline Discipline { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<HolidayRequestForm> HolidayRequestForms { get; set; }
public virtual Shift Shift { get; set; }
public virtual Site Site { get; set; }
public virtual UserRole UserRole { get; set; }
}
And View (just the table section):
<table class="table table-striped">
<tr>
<th>
Name
</th>
<th>
Start Date
</th>
<th>
Area
</th>
<th>
Discipline
</th>
<th>
Site Name
</th>
<th>
AL Category
</th>
<th>
Hours CF
</th>
<th>
Awarded Leave
</th>
<th>
Total Hours This Year
</th>
<th>
Hours Taken
</th>
<th>
Hours Remaining
</th>
<th>
Role
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FullName)
</td>
<td>
#Html.DisplayFor(modelItem => item.StartDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Area.Area1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Discipline.Discipline1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Site.SiteName)
<td>
#Html.DisplayFor(modelItem => item.ALCategory)
</td>
<td>
#Html.DisplayFor(modelItem => item.HoursCarriedForward)
</td>
<td>
#Html.DisplayFor(modelItem => item.AwardedLeave)
</td>
<td>
#Html.DisplayFor(modelItem => item.TotalHoursThisYear)
</td>
<td>
#Html.DisplayFor(modelItem => item.HoursTaken)
</td>
<td>
#Html.DisplayFor(modelItem => item.EntitlementRemainingThisYear)
</td>
<td>
#Html.DisplayFor(modelItem => item.UserRole.RoleName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.EmployeeID }, new { #class = "btn-xs btn-warning glyphicon glyphicon-pencil" })
#Html.ActionLink("Details", "Details", new { id = item.EmployeeID }, new { #class = "btn-xs btn-info glyphicon glyphicon-info-sign" })
#Html.ActionLink("Delete", "Delete", new { id = item.EmployeeID }, new { #class = "btn-xs btn-danger glyphicon glyphicon-trash" })
</td>
</tr>
}
</table>
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
I'd like it so that only managers/Admins assigned to certain sites could only view those sites and none else. Regular Users don't have access to this page.
Is this possible to do in mvc??

Related

How do you create a view that is specific to an object you create with the database?

I'm doing a hobby project a bug tracker.
And i want to be able to create a project with my database that I will be able to click on and then get a view where i can log information about the project and be able to make tickets for the project.
I have made two models, a project model then a ticket model I have created a one to many relationship between them. And i also made two controllers one for project and one for ticket.
Both project and ticket can perform CRUD operations. The only problem is that I do not really know how to get them put together in the project, to get details about an individual project.
I have a relationship between the models. But how do I get a view that is specific to my project?
My models
public class Project
{
[Key]
public int Project_Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
public DateTime Created { get; set; }
List<Ticket> Tickets { get; set; }
}
public class Ticket
{
[Key]
public int Ticket_Id { get; set; }
[Required]
public string TicketName { get; set; }
[Required]
public string TicketDescription { get; set; }
public DateTime TicketCreated { get; set; }
public string TicketPriority { get; set; }
public string TicketType { get; set; }
[ForeignKey("Project")]
public int Project_Id { get; set; }
public Project Project { get; set; }
}
I wrote a code for some like your situation, it could help you
Models
public class Procedure_s
{
[Key]
[HiddenInput(DisplayValue = false)]
public int PrId { get; set; }
[Required]
public string PrName { get; set; }
public string PrDescribe { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")]
public DateTime PrStartDate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")]
public DateTime PrEndDate { get; set; }
public string PrNote { get; set; }
// foreign Keys
public int PtyId { get; set; }
[ForeignKey("PtyId")]
public virtual ProceType ProceType { get; set; }
}
public class ProceType
{
[Key]
[HiddenInput(DisplayValue = false)]
public int PtyId { get; set; }
[Required]
public string PtyName { get; set; }
public string PtyNote { get; set; }
//connected tables
public virtual IList<Procedure_s> Procedure_s { get; set; }
Controller:
Details Method
// GET: ProceTypes/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var proceType = await _context.ProceType
.Include(p => p.Procedure_s)
.FirstOrDefaultAsync(m => m.PtyId == id);
if (proceType == null)
{
return NotFound();
}
return View(proceType);
}
View:
Details page
#model DirManageSys.Models.TaskSys.ProceType
#{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>ProceType</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.PtyName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.PtyName)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.PtyNote)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.PtyNote)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="#Model.PtyId">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
<table id="tblData" class="table table-hover table-bordered text-black-50" style="width:100%">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Procedure_s[0].PrName)
</th>
<th>
#Html.DisplayNameFor(model => model.Procedure_s[0].PrStartDate)
</th>
<th>
#Html.DisplayNameFor(model => model.Procedure_s[0].PrEndDate)
</th>
<th>
#Html.DisplayNameFor(model => model.Procedure_s[0].PrDescribe)
</th>
<th>
#Html.DisplayNameFor(model => model.Procedure_s[0].PrNote)
</th>
<th>
#Html.DisplayNameFor(model => model.Procedure_s[0].ProceType)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Procedure_s)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.PrName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PrStartDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.PrEndDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.PrDescribe)
</td>
<td>
#Html.DisplayFor(modelItem => item.PrNote)
</td>
<td>
#Html.DisplayFor(modelItem => item.ProceType.PtyName)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.PrId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.PrId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.PrId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
this code show table of procedures on the Details page of proce type,
which View the
one-to-many relationship of two models
on razor page by showing information of first model and table of the second model

Save the List value during the post back, its get cleared when i try to access the list after clicking the button each time in MVC

Controller:
List<EmployeeSkill> emp = new List<EmployeeSkill>();
public ActionResult viewskills(EmployeeSkill objskillset)
{
emp .Add(objskillset);
return PartialView("_SkillListPartial", objskillset);
}
Model:
public int EmployeeID { get; set; }
[Required(ErrorMessage = "Please Enter Skill")]
public string SkillName { get; set; }
[Display(Name = "Experience (In Months)")]
[Required(ErrorMessage = "Please Enter Experience(In Months)")]
public Nullable<byte> ExperienceInMonths { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public string ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public Nullable<bool> IsActive { get; set; }
public virtual EmployeeDetail EmployeeDetail { get; set; }
View:
model IEnumerable<CISSEC.Models.EmployeeSkill>
<table class="table">
<tr>
<th> #Html.DisplayNameFor(model => model.SkillName) </th>
<th> #Html.DisplayNameFor(model => model.ExperienceInMonths)</th>
</tr>
#foreach (var item in Model) {
<tr>
<td> #Html.DisplayFor(modelItem => item.SkillName) </td>
<td> #Html.DisplayFor(modelItem => item.ExperienceInMonths) </td>
</tr>
}
</table>
Your list is not posted back because you do not render <input> elements for the properties of the list items. Use HiddenFor to render the inputs. Use a for loop so the modelbinder receives the correct index of the list items.
#for (var i = 0; i < Model.Count(); i++) {
<tr>
<td> #Html.HiddenFor(m => m[i].SkillName) </td>
<td> #Html.HiddenFor(m=> m[i].ExperienceInMonths) </td>
</tr>
}

Display a list in a view MVC 4

I have a model Course, a model Component and a model Evaluation:
public class Course
{
public virtual int CourseId { get; set; }
public virtual string Name { get; set; }
public virtual List<Component> Components { get; set; }
public virtual List<UserProfile> Users { get; set; }
public virtual List<Evaluation> Evaluation { get; set; }
}
public class Component
{
public virtual int ComponentId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual string NameComp { get; set; }
}
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual int UserId { get; set; }
public virtual UserProfile User { get; set; }
public virtual int Grade { get; set; }
}
I need to show in a view a table with all the users, all the components created and the grade for each one.
I tried this way:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
#foreach (var x in Model.Components)
{
<th>
#Html.DisplayFor(modelItem => x.NameComp)
</th>
}
<th></th>
</tr>
#foreach (var item in Model.Evaluation)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.User.UserName)
</td>
#foreach (var x in Model.Components)
{
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
}
<td>
</td>
</tr>
}
But this gives me all the components in one column, and i need one column for each component, and a grade for each one:
The code i have gives this:
Username - Component1Component2Component3
Test - 12
Test - 13
Test - 10
(example of result with username and grades)
And i need:
Username - Component1 - Component2 - Component3
Test - 12 - 13 - 10
(example of result with username and grades)
How can i do this? Thanks
The definition of Evaluations in Course should be:
public virtual IGrouping<string, Evaluation> Evaluations { get; set; }
The code should be:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
<th>
#foreach (var x in Model.Components)
{
#Html.DisplayFor(modelItem => x.NameComp)
}
</th>
<th></th>
</tr>
#foreach (var group in Model.Evaluations)
{
<tr>
<td>
#Html.DisplayFor(modelItem => group.Key)
</td>
#foreach (var item in group)
{
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
}
<td>
</td>
}
</tr>
You need to make sure the evaluation is in reference to a course component:
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual int ComponentId { get; set; }
public virtual Component Component { get; set; }
public virtual int UserId { get; set; }
public virtual UserProfile User { get; set; }
public virtual int Grade { get; set; }
}
Here are some test values:
var users = new List<UserProfile>
{
new UserProfile { UserId = 1, UserName = "Jim" },
new UserProfile { UserId = 2, UserName = "Sam" },
};
var components = new List<Component>
{
new Component { ComponentId = 1, NameComp = "Unit 1" },
new Component { ComponentId = 2, NameComp = "Unit 2" }
};
var course = new Course
{
Users = users,
Components = components.OrderBy(c => c.ComponentId).ToList(),
Evaluation = new List<Evaluation>
{
new Evaluation { User = users[0], ComponentId = components[0].ComponentId, Grade = 87 },
new Evaluation { User = users[0], ComponentId = components[1].ComponentId, Grade = 99 },
new Evaluation { User = users[1], ComponentId = components[0].ComponentId, Grade = 75 },
new Evaluation { User = users[1], ComponentId = components[1].ComponentId, Grade = 65 }
}
};
And following Razor view should do what you need:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
#foreach (var x in Model.Components)
{
<th>
#Html.DisplayFor(modelItem => x.NameComp)
</th>
}
<th></th>
</tr>
#foreach (var userEvaluation in Model.Evaluation.GroupBy(e => e.User))
{
<tr>
<td>
#Html.DisplayFor(modelItem => userEvaluation.Key.UserName)
</td>
#foreach (var x in Model.Components)
{
<td>
#(userEvaluation.FirstOrDefault(e => e.ComponentId == x.ComponentId)?.Grade)
</td>
}
<td></td>
</tr>
}
Watch out for this model, it has a lot of circular references, which can be problematic if you're using something like Entity Framework.

MVC 5 getting Multiple Models into a single view

Newbie to MVC, using MVC 5 and VS 2013.
Code first from existing database, EF6
Goal:
Want to show a listing of all models from the tblModel for an MVP listed in tblMVP
Below is the current state of the project and the runtime error:
Error:
System.Collections.Generic.IEnumerable<WebApplication2.Models.tblAccount>' does not contain a definition for 'tblModels' and no extension method 'tblModels' accepting a first argument of type System.Collections.Generic.IEnumerable<WebApplication2.Models.tblAccount> could be found (are you missing a using directive or an assembly reference?)
Models:
[Table("tblMVP")]
public partial class tblMVP
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public virtual tblAccount tblAccount { get; set; }
}
[Table("tblModel")]
public partial class tblModel
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public virtual tblAccount tblAccount { get; set; }
}
[Table("tblAccount")]
public partial class tblAccount
{
public tblAccount()
{
tblModels = new HashSet();
tblMVPs = new HashSet();
}
public int ID { get; set; }
public virtual ICollection tblModels { get; set; }
public virtual ICollection tblMVPs { get; set; }
}
Controller:
// GET: MVP
public ActionResult Index()
{
var tblAccounts = db.tblAccounts.Include(t => t.tblModels).Include(t => t.tblMVPs);
return View(db.tblAccounts.ToList());
}
View
#model IEnumerable<WebApplication2.Models.tblAccount>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.tblModels.partNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.AccountName)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.tblModels.partNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.AccountName)
</td>
</tr>
}
</table>
You're trying to do two different things. You have an IEnumerable<tblAccount>, which doesn't have properties, it just has a list of tblAccount.
So in the top, you're trying to get properties of the IEnumerable, but there aren't any.
In the bottom, you're iterating the IEnumerable, and getting properties of the tblAccount, which you are doing correctly.
So in the top section, you need to get a tblAccount from the IEnumerable so that you can get properties of it. Below is an example of how you can do it.
#model IEnumerable<WebApplication2.Models.tblAccount>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.First().tblModels.partNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.First().AccountName)
</th>
</tr>
Ultimately this is is the bare essentials version of what worked. For better or worse a direct relationship between the tblModel and tblMVP was created and the model loading in the controller was rearranged.
Models:
[Table("tblMVP")]
public partial class tblMVP
{
public tblMVP()
{
tblModels = new HashSet();
}
public int ID { get; set; }
public int AccountID { get; set; }
public string Description { get; set; }
public virtual tblAccount tblAccount { get; set; }
public virtual ICollection tblModels { get; set; }
}
[Table("tblModel")]
public partial class tblModel
{
[Key]
public int ModelID { get; set; }
public int AccountID { get; set; }
[Required]
[StringLength(50)]
public string partNumber { get; set; }
[StringLength(5000)]
public string description { get; set; }
public int? MVPID { get; set; }
public virtual tblMVP tblMVP { get; set; }
}
[Table("tblAccount")]
public partial class tblAccount
{
public tblAccount()
{
tblModels = new HashSet();
tblMVPs = new HashSet();
}
public int ID { get; set; }
[StringLength(150)]
public string AccountName { get; set; }
public int? AccountNumber { get; set; }
public virtual ICollection tblModels { get; set; }
public virtual ICollection tblMVPs { get; set; }
}
**Controller:**
// GET: MVP
public ActionResult Index()
{
var tblModels = db.tblModels.Include(t => t.tblAccount).Include(t => t.tblMVP).ToList();
return View(tblModels.ToList());
}
View
#model IEnumerable<MDLX_Bootstrap_V5.Models.tblModel>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.tblAccount.AccountName)
</th>
<th>
#Html.DisplayNameFor(model => model.partNumber)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.tblAccount.AccountName)
</td>
<td>
#Html.DisplayFor(modelItem => item.partNumber)
</td>
</tr>
}
</table>

Display Country Entity inside the Index

I have an entity called Fixture, and basically I want to display some fixtures on the page.
My Model is as follows :-
public class Fixture
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int FixtureId { get; set; }
[Display(Name = "Fixture Date")]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? FixtureDate { get; set; }
public DateTime? FixtureTime { get; set; }
public int? CityId { get; set; }
public City City { get; set; }
public int CountryIdA { get; set; }
public int CountryIdB { get; set; }
public int? ScoreA { get; set; }
public int? ScoreB { get; set; }
public Round Round { get; set; }
public int? RoundId { get; set; }
public List<Scorer> Scorers { get; set; }
}
and my ViewModel is as follows :-
public class FixtureViewModel
{
public Fixture Fixture { get; set; }
public IEnumerable<Fixture> FixtureList { get; set; }
public IEnumerable<GroupCountry> GroupCountryList { get; set; }
public IEnumerable<Group> GroupList { get; set; }
public string CountryNameA { get; set; }
public string CountryNameB { get; set; }
}
and I am displaying them in this index page :-
<table>
<tr>
<th>
#Html.DisplayName("Date")
</th>
<th>
#Html.DisplayName("Country A")
</th>
<th>
#Html.DisplayName("Country A")
</th>
<th>
#Html.DisplayName("Score A")
</th>
<th>
#Html.DisplayName("Score B")
</th>
<th>
#Html.DisplayName("Round")
</th>
<th></th>
</tr>
#foreach (Fixture item in Model.FixtureList)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FixtureDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryIdA)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryIdB)
</td>
<td>
#Html.DisplayFor(modelItem => item.ScoreA)
</td>
<td>
#Html.DisplayFor(modelItem => item.ScoreB)
</td>
<td>
#Html.DisplayFor(modelItem => item.Round.RoundName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new {id = item.FixtureId}) |
#Html.ActionLink("Details", "Details", new {id = item.FixtureId}) |
#Html.ActionLink("Delete", "Delete", new {id = item.FixtureId})
</td>
</tr>
}
</table>
Now in the index page, I wish to display something like this :-
<td>
#Html.DisplayFor(modelItem => item.CountryIdA.Country.CountryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CountryIdB.Country.CountryName)
</td>
How can I achieve that?
I added a navigation item Country in the Model, however I still cannot display the correct CountryName.
Thanks for your help and time
Well CountryIdA and CountryIdB are just Integers. If you are trying to say...
Find a fixture with CountryIdA/B, then get it's Country, and then CountryName
then this is not appropriate to put in a view. Your view should not handle any data access, that is the job of your controller/model. I would suggest adding two Country properties to your view model, one for IdA and one for IdB. Then you can populate these in your controller action and have access to them in your view.
Your controller might look something like...
ViewModel.CountryA = Countries.Where(x => x.CountryID = ViewModel.CountryIdA)
You can extend Fixture in your model by creating a partial class Fixture in the same namespace, create two custom properties CountryIdA/B that does a lookup for the currect IDs.

Resources