0

I am working on a library management website. As user of the application, I want to be able to create new employees, for example ceo, manager and regular employee. I have done that and it is working.

But I want to be able to the employees to manage each other depending on their role, for example I want the:

  1. CEO to manage managers but not employees
  2. Managers to manage other managers and employees
  3. No one can manage the CEO

To do that I have tried to map managerID against the id of the employee (I don't know if its a good idea):

public partial class Employees
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] // For autoincrement
    //public int EmployeeId { get; set; }
    //[Required]

    //[Index]
    //public int TheManagerId { get; set; } // Manager ID Foreign Key
    //[Required]

    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Nullable<decimal> Salary { get; set; }
    public Nullable<bool> IsCEO { get; set; }
    public Nullable<bool> IsManager { get; set; }
    public Nullable<int> ManagerId { get; set; }
}

And this is how my Create.cshtml looks like:

@model LibraryProject.Employees

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>Employees</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })

    <div class="form-group">
        @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Salary, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Salary, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Salary, "Your input should be an integer between 1-10.", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.IsCEO, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            <div class="checkbox">
                @Html.EditorFor(model => model.IsCEO)
                @Html.ValidationMessageFor(model => model.IsCEO, "", new { @class = "text-danger" })
            </div>
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.IsManager, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            <div class="checkbox">
                @Html.EditorFor(model => model.IsManager)
                @Html.ValidationMessageFor(model => model.IsManager, "", new { @class = "text-danger" })
            </div>
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.ManagerId, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.ManagerId, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.ManagerId, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

@using (Html.BeginForm())
{
    if (!string.IsNullOrEmpty(ViewBag.ErrorMessage5))
    {
        <div>
            <p>

                <span style="color:red;">@ViewBag.ErrorMessage5</span>

            </p>
        </div>
    }
    <div class="form-horizontal" />
}

And this is how my Employee controller looks like:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using LibraryProject;

namespace LibraryProject.Controllers
{
    public class EmployeesController : Controller
    {
        private LibraryDbEntities db = new LibraryDbEntities();

        // GET: Employees
        public ActionResult Index()
        {
            // Linq queries to show all the employees separately, is used to not mixed them up.
            var getCeo = from employeCEO in db.Employees 
                         where employeCEO.IsCEO == true 
                         select employeCEO;
          
            var getEmployee = from employee in db.Employees 
                              where employee.IsCEO == false && employee.IsManager == false  
                              select employee;
           
            var getManager = from employeeManager in db.Employees 
                             where employeeManager.IsManager == true && employeeManager.IsCEO == false  
                             select employeeManager;

            IEnumerable<Employees> list = getCeo.Concat(getEmployee).Concat(getManager);
           
            return View(list.ToList());
        }

        public ActionResult CEO()
        {
           // linq query used to display ceo in a separate view
            var getCeo = from employeCEO in db.Employees  
                         where employeCEO.IsCEO == true 
                         select employeCEO;
            return View(getCeo);
        }

        public ActionResult TheManager()
        {
            // linq query used to display manager in a separate view
            var getManager = from employeeManager in db.Employees 
                             where employeeManager.IsManager == true && employeeManager.IsCEO == false 
                             select employeeManager;
            return View(getManager);
        }

        public ActionResult RegularEmployee()
        {
            // linq query used to display employee in a separate view
            var getEmployee = from employee in db.Employees 
                              where employee.IsCEO == false && employee.IsManager == false 
                              select employee;
            return View(getEmployee);
        }

        // GET: Employees/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Employees employees = db.Employees.Find(id);

            if (employees == null)
            {
                return HttpNotFound();
            }

            return View(employees);
        }

        // GET: Employees/Create
        public ActionResult Create()
        {
            ViewBag.Employees = new SelectList(db.Category, "Id", "Employees");
            return View();
        }

        // POST: Employees/Create
        // To protect from overposting attacks, enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "Id,FirstName,LastName,Salary,IsCEO,IsManager,ManagerId")] Employees employees)
        {
            if (ModelState.IsValid)
            {
                //salary coefficient for the employees
                decimal salaryCeo = 2.725M;
                decimal salaryManager = 1.725M;
                decimal employeeSalary = 1.125M;

                var ceo = db.Employees.Count(x => x.IsCEO == true);

                //Checks if there is a ceo
                if (ceo == 0)
                {
                    employees.Salary = employees.Salary * salaryCeo; // calculate ceo salary

                    db.Employees.Add(employees);
                    db.SaveChanges();

                    return RedirectToAction("Index");
                } 
                else if (ceo == 1 && employees.IsCEO == true) // check if there is a ceo, if yes show errormessage
                {
                    ViewBag.ErrorMessage5 = "There is already a CEO in the database! You cannot create a second one!";
                } 
                else if(employees.IsCEO == false && employees.IsManager == false) // check if the employee is ceo or manager, if false its a regular employee
                {
                    employees.Salary = employees.Salary * employeeSalary; // calculate regular employees salary
                    db.Employees.Add(employees);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
                else if (employees.IsCEO == false && employees.IsManager == true) // manager
                {
                    employees.Salary = employees.Salary * salaryManager; // manager salary
                    db.Employees.Add(employees);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }

            return View(employees);
        }

        // GET: Employees/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Employees employees = db.Employees.Find(id);

            if (employees == null)
            {
                return HttpNotFound();
            }

            return View(employees);
        }

        // POST: Employees/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,FirstName,LastName,Salary,IsCEO,IsManager,ManagerId")] Employees employees)
        {
            if (ModelState.IsValid)
            {
                db.Entry(employees).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(employees);
        }

        // GET: Employees/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Employees employees = db.Employees.Find(id);

            if (employees == null)
            {
                return HttpNotFound();
            }

            return View(employees);
        }

        // POST: Employees/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Employees employees = db.Employees.Find(id);
            db.Employees.Remove(employees);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

I KNOW IT IS SOME CODE THERE... BUT I HOPE SOMEONE IS OUT THERE TO HELP.

THANKS.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • seems like you could just include a "rank" field. Then simple logic of if employee1.rank > employee2.rank (allow/show manage control...) or case/switch based on rank#. If need to specify specific managers for specific employees consider a many-to-many relationship... (a table with uid/employeeid/managerid): https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#other-relationship-patterns – pcalkins Oct 07 '20 at 22:07
  • @pcalkins could you please give a code example based on my code? –  Oct 08 '20 at 05:57
  • not sure I understand your code enough to give a specific answer. I thought on it more and I think what you really want is just a "Title" field in your Employee table. Then case/switch based on the employee's title. (For instance link to different pages /controllers depending on title... or create a more dynamic single page.) Using authorization as the answer below lists seems useful too for action/page based permissions. – pcalkins Oct 08 '20 at 21:50

1 Answers1

0

But I want to be able to the employees to manage each other depending on their role, for example I want the:

  1. CEO to manage managers but not employees

  2. Managers to manage other

  3. managers and employees No one can manage the CEO

I think what you want to achieve is Authorize, not the relationship in table.

For how to Customize a Authorize Attribute, You can refer to this thread.

mj1313
  • 7,930
  • 2
  • 12
  • 32