Available here: https://github.com/develop-me/bagajob/wiki/A-Code-of-Conduct-for-Open-Source-Projects
Never commit directly to the master branch. Create a new feature branch from the development branch, and make a pull request for a team-mate to review and merge.
The Vagrant Box set up to use Laravel's Homestead image. To get started:
-
Clone this repo and
cd
into the new directory -
In your new directory, run
composer install
-
Run
vendor/bin/homestead make
-
Copy the
.env.example
file to a new.env
file:cp .env.example .env
-
Update passwords in your
.env
file- The admin user is controlled by these environment variables and will be created when the database is seeded
- ADMIN_USER_NAME="Bagajob Admin"
- ADMIN_USER_EMAIL=[email protected]
- ADMIN_USER_PASSWORD= *****
- If you need email, set these api keys as well, they can be accessed from the bagajob mailjet account
- MAILJET_APIKEY= *****
- MAILJET_APISECRET= *****
- The admin user is controlled by these environment variables and will be created when the database is seeded
-
Run
vagrant up
-
ssh to the virtual machine:
vagrant ssh
-
Navigate to new
code
folder:cd code
-
Run the database migrations:
artisan migrate
-
Seed the database with example data:
artisan db:seed
UsersTableSeeder.php
adds the admin userJobsTableSeeder.php
adds 10 Users, each with 10 jobs associated.AppNoteSeeder.php
adds 2 application notes to each jobInterviewSeeder.php
adds 2 interviews to each job
-
Create the Passport authentication keys:
php artisan passport:install
Visit http://homestead.test
on Mac or http://localhost:8000
on Windows:
A: Run artisan passport:install
to create the personal access client keys again
A:
First, make sure you're only running this on your local machine and NOT the Vagrant box.
Second, run this command to increase your memory limit, you can use -1 to make it unlimited if neccessary.
php -d memory_limit=-1 $(which composer) update
Also see this page: https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors
Q: When I visit http://homestead.test
on Mac or http://localhost:8000
on Windows, I get an Error 500: Internal Server Error
A:
Reload the vagrant box and provision it:
vagrant reload --provision
Generate a new app key:
php artisan key:generate
Vagrant was unable to mount VirtualBox shared folders. This is usually
because the filesystem "vboxsf" is not available. This filesystem is
made available via the VirtualBox Guest Additions and kernel module.
Please verify that these guest additions are properly installed in the
guest. This is not a bug in Vagrant and is usually caused by a faulty
Vagrant box. For context, the command attempted was:
mount -t vboxsf -o dmode=777,fmode=666,uid=1000,gid=1000 var_www /var/www
The error output from the command was:
: No such device
A:
First, install the vagrant-vbguest
plugin:
vagrant plugin install vagrant-vbguest
Next, initialise the plugin:
vagrant vbguest
- The bagajob API lives on AWS, using the [email protected] account as the login user.
- Server: EC2 t2.micro
- Region: eu-west-2 (london)
- OS: Ubuntu 20.04
- AMI: ami-05c424d59413a2876 (UbuntuServer 20.04LTS(HVM), SSDVolumeType)
- Software:
- Nginx: HTTP server software
- MySQL: database management system
- PHP: programming language
- Git: file management
- Composer: PHP package manager
- SSH Keys: for authentication
-
To access the EC2 instance you'll need an ssh keypair, which you likely already have from the DevelopMe course. Run
tail ~/.ssh/id_rsa.pub
at the command prompt on your machine and provide the output to Kieran/Nik. -
Someone with access to the EC2 instance will then add this to
~/.ssh/authorized_keys
on the server to grant you ssh access. -
Add the below entry to your ssh configuration file, replace
<alias>
with anything you want and<your-server-key>
with the name of the .pem file you have at~/.ssh/
code ~/.ssh/config
Host <alias> ec2-3-8-127-159.eu-west-2.compute.amazonaws.com
HostName ec2-3-8-127-159.eu-west-2.compute.amazonaws.com
User ubuntu
IdentityFile ~/.ssh/<your-server-key>.pem
IdentitiesOnly yes
- Updating the code on the EC2 instance is a breeze with capistrano
- Install bundle
- On your machine run
gem install bundler
- Make sure you have an up to date copy of the repo that contains
Gemfile
, cd to the project directory and runbundle install
- Make sure your recent changes are tested and synced with the
master
branch (usually through merging a pull request) - Run
bundle exec cap production deploy
- This will make capistrano do the following:
- Pull down the latest version of the repo to the server
- Copy the files into a new timestamped releases directory
- Link any shared files (.env, the storage directory)
- Run composer install
- Link the current directory to the latest
For more information check out Chapter 25 - Capistrano
in the DevelopMe Notes
If you deploy a site and then realise the code wasn’t quite ready, you can go back to the previous version by running:
bundle exec cap production deploy:rollback
All requests should:
- For non-production use the basename
https://homestead.test/api/
- For production use the basename
https://bagajob-api.developme.space/api/
- Be sent with the
Accept: application/json
header.
Registration and Login
POST /register
POST /login
POST /reset-password-without-token
POST /reset-password-with-token
Users
PATCH /user/:userId
DELETE /user/:userId
Jobs
GET /user/:userId/jobs
POST /user/:userId/jobs
GET /user/:userId/jobs/:jobId
PATCH /user/:userId/jobs/:jobId
DELETE /user/:userId/jobs/:jobId
Interviews
GET /user/:userId/jobs/:jobId/interviews
POST /user/:userId/jobs/:jobId/interviews
GET /user/:userId/jobs/:jobId/interviews/:interviewId
PATCH /user/:userId/jobs/:jobId/interviews/:interviewId
DELETE /user/:userId/jobs/:jobId/interviews/:interviewId
Application Notes
GET /user/:userId/jobs/:jobId/app-notes
POST /user/:userId/jobs/:jobId/app-notes
GET /user/:userId/jobs/:jobId/app-notes/:appNoteId
PATCH /user/:userId/jobs/:jobId/app-notes/:appNoteId
DELETE /user/:userId/jobs/:jobId/app-notes/:appNoteId
{
"name": "<user name>", // REQ, full name
"email": "<email>", // REQ, valid email, not the same as another in the database
"password": "<password>" // REQ, password
}
{
"success": {
"token": "<token>"
},
"user": {
"id": "<ID>",
"name": "<user name>",
"email": "<email>",
"created_at": "2020-09-01 14:22:46"
}
}
- Missing name
- Missing email
- Missing password
- Duplicate User (email must be unqiue)
{
"message": "The given data was invalid.",
"errors": {
"name": [
"A name is required to create a user account"
],
"email": [
"A email is required to create a user account"
],
"password": [
"A password is required to create a user account"
],
"email": [
"A user account exists already with this email"
],
}
}
- NOTE:
username
maps toemail
in this case
{
"username": "<user email>", // REQ, valid user email
"password": "<password>" // REQ, password
}
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "<token>",
"refresh_token": "<token>",
"user": {
"id": 20,
"name": "<user name>",
"email": "<email>",
"created_at": "2020-09-01 14:22:46"
}
}
- Missing username/password
{
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `< missing >` parameter",
"message": "<same as error_description>"
}
- Invalid username/password
{
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": "",
"message": "<same as error_description>"
}
- If the frontend tries to make a request to any of the non-authentication workflow related routes without the proper Bearer Token, they will receive this response:
{
"message": "Unauthenticated."
}
{
"email": "<email>", // REQ, valid user email
}
{
"message": "Reset Password email successfully sent"
}
- No email supplied/invalid email format
{
"message": "The given data was invalid.",
"errors": {
"email": [
"An email is required to reset the password" // "A valid email must be used to reset the password"
]
}
}
- User does not exist with that email
{
"message": "An account does not exist with this email address"
}
- Email failed
{
"message": "An error has occured sending the reset password email, please try again",
"error": "<error message>"
}
{
"email": "<email>", // REQ, valid user email
"password": "<new password>", // REQ, new password
"token": "<reset token>", // REQ, valid reset token from email
}
{
"message": "Password Reset Successful",
"user": {
"id": 21,
"name": "<name>",
"email": "<email>",
"created_at": "2020-09-03 11:16:06"
},
"token": "<bearer token>"
}
- Similar email, password, token validation as before (required)
- Invalid token, or they've already reset their password
{
"message": "Password token invalid, please submit a new password reset request"
}
{
"email": "<email>", // OPT, valid user email, not duplicate
"name": "<user name>" // OPT, string
}
- Returns the user object
{
"user": {
"id": 23,
"name": "<name>",
"email": "<email>",
"created_at": "2020-09-04 14:15:57"
}
}
- Trying to update a different user than you are logged in as
{
"message": "You cannot edit a user other than your own"
}
- Trying to update to a Duplicate email in the database
{
"message": "The given data was invalid.",
"errors": {
"email": [
"A user account exists already with this email"
]
}
}
- Incorrect format(s) name or email
{
"message": "The given data was invalid.",
"errors": {
"email": [
"The email must be a valid email address."
]
}
}
- Returns a 204 - No Content response
- Trying to delete a user other than your own
{
"message": "You cannot delete a user other than your own"
}
- Trying to delete a user that does not exist
{
"message": "No query results for model [App\\User] <ID>"
}
Returns a subset of information from all of the specified user's jobs as JSON:
{
"data": [
{
"id": 21,
"title": "Architect",
"company": "Halvorson, Runolfsson and Gutmann",
"active": 1,
"stage": "1"
},
{
"id": 22,
"title": "Tire Builder",
"company": "Spinka-Lubowitz",
"active": 1,
"stage": "1"
},
]
}
Does not return interviews or notes
Adds a job to the database. The below is the minimum required JSON, all other fields optional.
{
"title" : "Senior Java Developer",
"company" : "Green Software Inc.",
"stage" : 1,
"active": 1
}
The newly created job with an Id (see GET request below)
Returns an individual job as JSON object where :jobId
is the job ID
{
"data": {
"id": 21,
"title": "Rental Clerk",
"company": "Sauer, Witting and Osinski",
"active": 1, // boolean (1 - true, 0 - false)
"location": "Bergemouth",
"salary": "56010.00",
"closing_date": "2021-05-22 22:05:29",
"date_applied": null,
"description": "Dicta dolorem aut id porro ut porro sit. Expedita nemo vel natus eos ipsa quasi. Deleniti placeat non qui quibusdam adipisci amet et at.",
"stage": "1",
"cv": "CV_June_2020.pdf", // string of the filename, not actually storing files at this time
"cover_letter": "fullstack_cover_July_2020.pdf", // string of the filename, not actually storing files at this time
"interviews": ["..."],
"application_notes": ["..."]
}
}
JSON with fields to update
The updated job
204 No Content
Returns all of the specified job's interviews as JSON:
{
"data": [
{
"id": 41,
"job_id": 21,
"interview_date": "2019-12-04 00:00:00",
"format": "video_call",
"interviewer": "Prof. Ozella Stark II",
"notes": "Quis aut commodi nam id consectetur. Et veniam magnam et incidunt est officiis magnam consequatur."
},
{
"id": 42,
"job_id": 21,
"interview_date": "2008-07-14 00:00:00",
"format": "online_testing",
"interviewer": "Leonardo Bayer DVM",
"notes": "Voluptatem numquam ea a quaerat sunt. Laudantium aperiam aut pariatur perferendis nisi possimus."
}
]
}
{
"interview_date": "2020-09-09", // REQ, date
"format": "telephone", // REQ, set - 'online_testing','telephone', 'video_call', 'in_person'
"interviewer": "Johnny", // OPT, string, max 250
"notes": "Twas the night before xmas and all through the house" // OPT, string, max 500
}
The newly created interview as JSON
Return 1 interview with the specified :interviewId
{
"data": {
"id": 42,
"job_id": 21,
"interview_date": "2008-07-14 00:00:00",
"format": "online_testing",
"interviewer": "Leonardo Bayer DVM",
"notes": "Voluptatem numquam ea a quaerat sunt. Laudantium aperiam aut pariatur perferendis nisi possimus."
}
}
JSON with fields to update
The updated interview
204 No Content
Returns all of the specified job's application notes as JSON:
{
"data": [
{
"id": 41,
"job_id": 21,
"date": "1998-06-17",
"data": "Illo tempora sequi ea quos. Et ut praesentium aut. Perspiciatis voluptas natus nisi similique. Architecto animi unde eum doloribus voluptatum in."
},
{
"id": 42,
"job_id": 21,
"date": "2008-02-01",
"data": "Est totam magnam ratione non ut ut qui. Sequi quia exercitationem ratione iure ullam et in et. Consequatur qui qui enim."
}
]
}
{
"date": "2020-10-10", // REQ, date
"data": "xmas and all through the house" // REQ, string, max 500
}
The newly created application notes as JSON
Return 1 applicaiton note with the specified :appNoteId
{
"data": {
"id": 42,
"job_id": 21,
"date": "2008-02-01",
"data": "Est totam magnam ratione non ut ut qui. Sequi quia exercitationem ratione iure ullam et in et. Consequatur qui qui enim."
}
}
JSON with fields to update
The updated interview
204 No Content
Laravel has the most extensive and thorough documentation and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
- Simple, fast routing engine.
- Powerful dependency injection container.
- Multiple back-ends for session and cache storage.
- Expressive, intuitive database ORM.
- Database agnostic schema migrations.
- Robust background job processing.
- Real-time event broadcasting.
Laravel is accessible, powerful, and provides tools required for large, robust applications.
- Check out the official docs at: box.scotch.io
- Read the getting started article
- Read the 3.5 release article