All the sources so far

Here is source\app.d:

import vibe.vibe;
import empcontrol;

void main()
{
  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  settings.sessionStore = new MemorySessionStore;
  auto router = new URLRouter;
  router.get("*", serveStaticFiles("public/"));
  router.registerWebInterface(new EmployeeController);
  auto listener = listenHTTP(settings, router);
  scope (exit) listener.stopListening();
 
  runApplication();
}

Here is source\empcontrol.d:

module empcontrol;
import vibe.vibe;
import empmodel;

struct User 
{
  bool loggedIn;
  string email;
}

class EmployeeController
{
  private EmployeeModel empModel;
  private string realm = "The Lorem Ipsum Company";
  private SessionVar!(User, "user") m_user;
 
  this()
  {
    empModel = new EmployeeModel;
  }
  
  void index(string _error = null)
  {
    string error = _error;
    m_user = User.init;
    terminateSession;
    render!("index.dt", error);
  }
  
  @auth
  void getAddEmployee(string _authUser, string _error = null)
  {
    string error = _error;
    render!("empadd.dt", departments, paygrades, provinces, error);
  }
  
  @errorDisplay!getAddEmployee
  void postAddEmployee(Employee e)
  {
    import std.file;
    import std.path;
    import std.algorithm;
    import vibe.http.auth.digest_auth;
    auto pic = "picture" in request.files;
    if(pic !is null)
    {
      string photopath = "none yet";
      string ext = extension(pic.filename.name);
      string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
      if(canFind(exts, ext))
      {
        photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
        string dir = "./public/uploads/photos/";
        mkdirRecurse(dir);
        string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
        try moveFile(pic.tempPath, NativePath(fullpath));
        catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath), true);
      }
      e.photo = photopath;
    }
    if(e.phone.length == 0) e.phone = "(123) 456 7890";
    if(e.paygd.length == 0) e.paygd = "none yet";
    if(e.postcode.length == 0) e.postcode = "A1A 1A1";
    e.pword = createDigestPassword(realm, e.email, e.pword);
    empModel.addEmployee(e);
    redirect("all_employees");
  }
  
  @auth
  void getAllEmployees(string _authUser, string _error = null)
  {
    string error = _error;
    Employee[] emps = empModel.getEmployees;
    render!("emplistall.dt", emps, error);
  }
  
  @auth
  void getEditEmployee(string _authUser, int id, string _error = null)
  {
    string error = _error;
    Employee e = empModel.getEmployee(id);
    render!("empedit.dt", e, departments, paygrades, provinces, error);
  }
  
  @errorDisplay!getEditEmployee
  void postEditEmployee(Employee e)
  {
    import std.file;
    import std.path;
    import std.algorithm;
    import vibe.http.auth.digest_auth;
    string photopath = e.photo;
    auto pic = "picture" in request.files;
    if(pic !is null)
    {
      string ext = extension(pic.filename.name);
      string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
      if(canFind(exts, ext))
      {
        photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
        string dir = "./public/uploads/photos/";
        mkdirRecurse(dir);
        string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
        try moveFile(pic.tempPath, NativePath(fullpath));
        catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath), true);
      }
    }
    e.photo = photopath;
    if(e.phone.length == 0) e.phone = "(123) 456 7890";
    if(e.paygd.length == 0) e.paygd = "none yet";
    if(e.postcode.length == 0) e.postcode = "A1A 1A1";
    e.pword = createDigestPassword(realm, e.email, e.pword);
    empModel.editEmployee(e);
    redirect("all_employees");
  }
  
  @auth
  void getDeleteEmployee(string _authUser, int id, string _error = null)
  {
    string error = _error;
    Employee e = empModel.getEmployee(id);
    render!("empdelete.dt", e, error);
  }
  
  @errorDisplay!getDeleteEmployee
  void postDeleteEmployee(int id)
  {
    empModel.deleteEmployee(id);
    redirect("all_employees");
  }
  
  @auth
  @errorDisplay!getAllEmployees
  void postFindEmployee(string _authUser, string fname, string lname)
  {
    import std.uni; //so we can use the toUpper() function
    string first = toUpper(fname);
    string last = toUpper(lname);
    Employee e = empModel.findEmployee(first, last);
    enforce(e != Employee.init, fname ~ " " ~ lname ~ " not found.");
    render!("employee.dt", e);
  }
  
  @errorDisplay!index
  void postLogin(string email, string password)
  {
    import vibe.http.auth.digest_auth;
   
    auto scrambled = createDigestPassword(realm, email, password);
    bool isAdmin = empModel.isAdmin(email, scrambled);
    enforce(isAdmin, "Email and password combination not found.");
    User user = m_user;
    user.loggedIn = true;
    user.email = email;
    m_user = user;
    redirect("all_employees");
  }
  
  private enum auth = before!ensureAuth("_authUser");
  
  
  private string ensureAuth(HTTPServerRequest req, HTTPServerResponse res)
  {
    if(!m_user.loggedIn) redirect("/");
    return m_user.email;
  }
  mixin PrivateAccessProxy;
}

And here is source\empmodel.d:

Here is views\cssformgrid.dt:

Here is views\csstable.dt:

Here is views\empadd.dt:

Here is views\empdelete.dt:

Here is views\empedit.dt:

Here is views\emplistall.dt:

Here is views\employee.dt:

Here is views\index.dt:

Here is views\layout.dt:

Here is views\menu.dt:

Here is views\footer.dt:

Here is views\styles.dt:

And here is dub.json:

Now on to the timekeeping system.

Last updated