A simple portal that handles vacation requests.
The backend has been written in PHP and exposes a REST API.
The frontend that consumes the API, is a single page application (SPA) implemented with the help of Vue.js javascript framework.
Below you will find the necessary documentation with instructions on how to run this project.
.
├── backend/ # Source files of the backend
│ ├── sql/ # A database dump
│ ├── .env.sample # A sample .env file that contains the required environment variables
│ ├── composer.json # Project's composer file (dependencies, autoload)
│ ├── ...
├── frontend/ # Source files of the frontend
│ ├── ...
├── documentation/ # Documentation related files
│ ├── eer-diagram/ # An EER diagram of the database schema
│ ├── phpdoc/ # Documentation files that has been generated with phpDocumentor
│ ├── postman-collection/ # A postman collection with all the endpoints of the api and examples
│ ├── screenshots/ # Some screenshots that demonstrating the frontend interface
└── docker-compose.yml # A docker-compose yaml file to run the project easily
I provide some instructions on how to run the project down below. You have the option to use the provided docker setup or run in manually.
Let's start with docker, as it is the easiest option. Just run the command below or follow the detailed instructions. Make sure though that the ports 80 (backend), 8080(frontend), 8081(phpmyadmin that used during development) are not occupied in your system as they get exposed by the docker containers.
git clone https://github.com/takisrs/vacation-portal.git && \
cd vacation-portal && \
mv backend/.env.sample backend/.env && \
docker-compose up
Detailed instructions:
- Clone this repo
git clone https://github.com/takisrs/vacation-portal.git
- Move to the project's folder
cd vacation-portal
- Rename the provided sample .env file located in the backend folder which keeps the necessary configuration
mv backend/.env.sample backend/.env
. It is safe to keep the defaults. - Build the images and spin up the containers with
docker-compose up
- You can access the frontend at http://localhost:8080
You could upload the files of the backend (backend/*
) in the web server of your choice but make sure to do the steps below:
- Of course, you will need a mysql server and you will have to import the dump file
backend/sql/dump.sql
- Use the provided .env.sample file and make a .env file where you will have to adjust the configuration (about the connection to the mysql and the smtp server).
- Install the required dependencies with
composer install
- Install the required dependecies with
npm install
- Serve the app in dev mode with
npm run serve
or build it withnpm run build
and move thefrontend/dist
in the webserver of your choice
The db dump includes the following demo accounts that you may use:
User
demo@vacationapp.gr
user123#
Admin
admin@vacationapp.gr
admin123#
Some key notes about the backend:
- Requires PHP 7.4 with the pdo_mysql extension
- Follows the MVC architecture
- Exposes a REST API
- The authentication / authorization is performed with JWT access tokens
- Each class / method is documented with DocBlocks
- You may find the defined routes at
backend/src/VacationApp.php
, so you could follow the flow of the application starting from there.
The rest api exposes the endpoints below. Any required payload is given as a json in the body of the request.
Each endpoint, except the login one, requires an authorization bearer token in the headers.
POST /auth/login
public Returns a token to the successfully authenticated users
GET /users
admin access Returns a list of all users
POST /users
admin access Creates a new user
GET /users/:id
admin access Return user's details
POST /users/:id
admin access Updates a user
GET /applications
user access Returns a list of applications of the authorized user
POST /applications
user access Creates a new application
POST /applications/:id/approve
admin access Approves an application
POST /applications/:id/reject
admin access Rejects an application
You may also find a postman collection at /documentation/postman-collection/collection.json
in case you want to check the above endpoints.
- \takisrs\VacationApp
- \takisrs\Controllers\ApplicationController
- \takisrs\Controllers\UserController
- \takisrs\Controllers\AuthController
- \takisrs\Core\Router
- \takisrs\Core\MySQLConnection
- \takisrs\Core\Controller
- \takisrs\Core\Response
- \takisrs\Core\Model
- \takisrs\Core\HttpException
- \takisrs\Core\Authenticator
- \takisrs\Core\Request
- \takisrs\Helpers\EmailTemplate
- \takisrs\Models\Application
- \takisrs\Models\User
App's main class Initialize the Request, Response, Router objects. Contains the defined routes. Provides a catch block for the whole application execution.
Visibility | Function |
---|---|
public | __construct() : void |
public | init() : void App's main method. It all starts here. It wraps the whole execution in a try/catch block to catch any unhandled exeption and return a meaningful json response to the client. |
public | registerRoutes() : void Declares the routes that the app uses. |
Application Controller Methods related to applications' handling (list, create, approve, reject).
Visibility | Function |
---|---|
public | approve() : void Approves an application The method changes the status of an application to "approved", and informs the user with an email. |
public | create() : void Creates a new application and returns the result of the operation |
public | index() : void Retrieves and returns the list of applications of the authorized user |
public | reject() : void Rejects an application The method changes the status of an application to "rejected", and inform the user with an email. |
This class extends \takisrs\Core\Controller
User Controller Handles any request about users (list, view, create, update).
Visibility | Function |
---|---|
public | create() : void Creates a new user |
public | index() : void Retrieves and returns the list of all users |
public | single() : void Retrieves and returns the fields of the requested user |
public | update() : void Updates an user |
This class extends \takisrs\Core\Controller
Auth Controller Handles the requests regarding authentication, such as login, signup. Currently, only the login method has been implemented.
Visibility | Function |
---|---|
public | login() : void Login |
This class extends \takisrs\Core\Controller
Router class
Visibility | Function |
---|---|
public | __construct(\takisrs\Core\Request $request, \takisrs\Core\Response $response) : void Router constructor |
public | get(\string $pattern, \string $controller, \string $method, integer/\int $access) : void Registers a get route |
public | matchAndExtractParams(\string $uri, \string $pattern) : bool if uri matches the pattern or not Checks if uri matches the pattern and extracts the params |
public | post(\string $pattern, \string $controller, \string $method, integer/\int $access) : void Registers a post route |
public | run() : void Matches the request with the corresponding controller/method and processes it |
A class that handles the mysql connection Follows the singleton pattern.
Visibility | Function |
---|---|
public | __construct() : void Constructor |
public | getConnection() : \PDO Returns the PDO connection |
public static | getInstance() : \takisrs\Core\MySQLConnection Returns the instance of the MySQLConnection |
Base Controller class Each controller should extend this class.
Visibility | Function |
---|---|
public | __construct(\takisrs\Core\Request $request, \takisrs\Core\Response $response) : void Base controller constructor |
Response class A simple class that sends the api response
Visibility | Function |
---|---|
public | send(array $data) : void Sends a response to the client |
public | status(int $code) : \takisrs\Core\Response Sets the response status code |
Base Controller class Any model extends this class. Provides some methods that simplify SELECT, CREATE and UPDATE sql queries.
Visibility | Function |
---|---|
public | __construct() : void |
public | create() : object/null Performs an insert query |
public | find(integer/\int $id) : object/null Accepts an id and retrieves the corresponding record from the database |
public | findAll(\string $sort=null) : array Retrieves all the records of the corresponding table from the database |
public | findBy(array $params, \string $sort=null) : array/null array of objects Retrieves a list of records of the database and return an object for each record |
public | findOneBy(array $params) : object/null Retrieves a record from the database |
public | update() : bool Performs an update query |
protected | buildWhere(array $params) : array sql where clause and bind params Gets and array of field-value pairs and returns an sql where clause |
protected | getBindParams() : array Returns an array with the pdo bindings |
protected | mapResultToObject(array $record, \object $object=null) : object Maps the result of a select query to the corresponding model |
A simple HttpException class Throw this exception when you want to provide a meaningfull API response to the user with the appropiate status code. Any other exception type returns a 500 status code in the response.
Visibility | Function |
---|---|
public | __construct(\int $code=500, \string $message='' , \Throwable $previous=null) : voidHttpException constructor |
This class extends \Exception
This class implements \Throwable
A class that handles the tasks related to JWT authorization
Visibility | Function |
---|---|
public static | decodeToken(\string $jwt) : array The decoded data Receives a token, decodes it and returns the data |
public static | getToken(array $payload) : string a JWT token Encodes the given payload and returns a JWT token |
Request class Helps with the request manipullation.
Visibility | Function |
---|---|
public | authorizationToken() : string/null Retrieves the authorization token of the request |
public | body(\string $key=null) : mixed Retrieves a parameter from the json request body |
public | get(\string $key=null) : mixed Retrieves a $_GET parameter |
public | getMethod() : string the request method Returns the request method (POST, GET) |
public | getUri() : string the uri Returns the request uri |
public | header(\string $key=null) : mixed header value Retrieves a header from the request |
public | param(\string $key=null) : mixed Retrieves a param from the request according to the provided key |
public | post(\string $key=null) : mixed Retrieves a $_POST parameter |
public | setParam(\string $key, string/int/\string $value) : \takisrs\Core\Request Sets a route param |
public | setUser(\takisrs\Models\User $user) : \takisrs\Core\Request Sets the authentication user |
public | user() : \takisrs\Models\User Returns the authorized user of the request |
public | validate(array $rulesArr) : bool/null A simple validation method for all request params (get, post, body) |
Handles email templating and sending
Visibility | Function |
---|---|
public | __construct(\takisrs\Helpers\sting/\string $templatePath) : void Constructor |
public | getBody() : string Returns email's body |
public | getSubject() : string Returns email's subject |
public | replaceVar(string $key, string/int $value) : \takisrs\Helpers\self Replaces a variable in the html content with the provided value |
public | replaceVars(array $data) : \takisrs\Helpers\self Replaces all the variables in the html content of the email template |
public | send(\string $email) : void Sends the email |
Application Model class
Visibility | Function |
---|---|
public | approve() : boolean Approves the application (Updates status to "approved") |
public | days() : integer Returns the duration of the vacation in days |
public | isApproved() : boolean Returns true if the application has been approved |
public | isRejected() : boolean Returns true if the application has been rejected |
public | reject() : boolean Rejects the application (Updates status to "rejected") |
public | user() : \takisrs\Models\User Returns application's user object |
This class extends \takisrs\Core\Model
User Model class
Visibility | Function |
---|---|
public | applications() : \takisrs\Models\Application[]/null Returns an array of user's applications |
public | isAdmin() : boolean Returns true if the user is an admin |
public | isUser() : boolean Returns true if the user is a simple user |
This class extends \takisrs\Core\Model
Some key notes about the frontend:
- Requires nodejs 14 if you intend to set it up locally in a dev environment
- It is a SPA that has been built with the VueJS framework
- Communicates with the backend through the REST api
- Keeps a state about the logged in users and sends a bearer authorization token in the headers on each request