Used CKEditor for being able to edit the post body. Added the ability to make a post and send it to the backend. Formatted post on backend by moving images into respective directory with the post name and unique ID. Showed message if errored or succeeded.

Signed-off-by: rodude123 <rodude123@gmail.com>
This commit is contained in:
2023-06-26 03:54:25 +01:00
parent 88c5cc9508
commit 61b8d3a987
174 changed files with 895 additions and 187 deletions
+123 -8
View File
@@ -1,8 +1,12 @@
<?php
namespace api\blog;
use api\utils\imgUtils;
use DOMDocument;
use PDO;
use Psr\Http\Message\UploadedFileInterface;
require_once __DIR__ . "/../utils/config.php";
require_once __DIR__ . "/../utils/imgUtils.php";
/**
* Blog Data Class
@@ -14,10 +18,10 @@ class blogData
* Get all blog posts
* @return array - Array of all blog posts or error message
*/
function getBlogPosts(): array
public function getBlogPosts(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, body, tags FROM blog ORDER BY dateCreated DESC;");
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, body, categories FROM blog ORDER BY dateCreated DESC;");
$stmt->execute();
// set the resulting array to associative
@@ -36,10 +40,10 @@ class blogData
* @param string $ID - ID of the blog post to get
* @return array - Array of all blog posts or error message
*/
function getBlogPost(string $ID): array
public function getBlogPost(string $ID): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, featured, headerImg, body, tags FROM blog WHERE ID = :ID;");
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, featured, headerImg, body, categories FROM blog WHERE ID = :ID;");
$stmt->bindParam(":ID", $ID);
$stmt->execute();
@@ -58,10 +62,10 @@ class blogData
* Get the latest blog post
* @return array - Array of the latest blog post or error message
*/
function getLatestBlogPost(): array
public function getLatestBlogPost(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, featured, headerImg, body, tags FROM blog ORDER BY dateCreated DESC LIMIT 1;");
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, featured, headerImg, body, categories FROM blog ORDER BY dateCreated DESC LIMIT 1;");
$stmt->execute();
// set the resulting array to associative
@@ -79,10 +83,10 @@ class blogData
* Get featured blog post
* @return array - Array of the featured blog post or error message
*/
function getFeaturedBlogPost(): array
public function getFeaturedBlogPost(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, featured, headerImg, body, tags FROM blog WHERE featured = 1;");
$stmt = $conn->prepare("SELECT ID, title, dateCreated, dateModified, featured, headerImg, body, categories FROM blog WHERE featured = 1;");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -94,4 +98,115 @@ class blogData
return array("errorMessage" => "Error, blog post could not found");
}
/**
* Upload the images in the post to temp folder and return image location
* @param UploadedFileInterface $img - Image to upload
* @return string|array - String with error message or array with the location of the uploaded file
*/
public function uploadPostImage(UploadedFileInterface $img): string|array
{
$targetDir = "../blog/imgs/tmp/";
$imagUtils = new imgUtils();
$targetFile = $imagUtils->uploadFile($targetDir, $img);
$file = $targetDir . basename($img->getClientFilename());
if (file_exists($file))
{
return array("url" => $file);
}
if (!is_array($targetFile))
{
return $targetFile;
}
if (file_exists($targetFile["imgLocation"]))
{
return array("url" => $targetFile["imgLocation"]);
}
return "Couldn't upload the image";
}
/**
* Creates a new post directory, uploads the header image and moves the images from the
* temp folder to the new folder, then updates the post html to point to the new images, finally
* it creates the post in the database
* @param string $title - Title of the blog post
* @param string $body - Body of the blog post
* @param string $dateCreated - Date the blog post was created
* @param string $featured - Whether the blog post is featured or not
* @param string $categories - Categories of the blog post
* @param UploadedFileInterface $headerImg - Header image of the blog post
* @return int|string - ID of the blog post or error message
*/
public function createPost(string $title, string $body, string $dateCreated, string $featured, string $categories, UploadedFileInterface $headerImg): int|string
{
$conn = dbConn();
$targetDir = "../blog/imgs/" . $title . "_" . uniqid() . "/";
mkdir($targetDir, 0777, true);
$imagUtils = new imgUtils();
$targetFile = $imagUtils->uploadFile($targetDir, $headerImg);
if (!is_array($targetFile))
{
return $targetFile;
}
$htmlDoc = new DOMDocument();
$htmlDoc->loadHTML($body, LIBXML_NOERROR);
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
$imgs = $doc->getElementsByTagName('img');
$srcList = array();
foreach ($imgs as $img)
{
$src = $img->getAttribute("src");
$srcList[] = $src;
$fileName = basename($src);
$img->setAttribute("src", $targetDir . $fileName);
}
$files = scandir("../blog/imgs/tmp/");
foreach ($files as $file)
{
if ($file != "." && $file != "..")
{
if (!in_array("../blog/imgs/tmp/" . $file, $srcList))
{
unlink("../blog/imgs/tmp/" . $file);
}
else
{
rename("../blog/imgs/tmp/" . $file, $targetDir . $file);
}
}
}
$newBody = '';
foreach ($doc->childNodes as $node)
{
$newBody .= $htmlDoc->saveHTML($node);
}
$stmt = $conn->prepare("INSERT INTO blog (title, dateCreated, dateModified, featured, headerImg, body, categories)
VALUES (:title, :dateCreated, :dateModified, :featured, :headerImg, :body, :categories);");
$stmt->bindParam(":title", $title);
$stmt->bindParam(":dateCreated", $dateCreated);
$stmt->bindParam(":dateModified", $dateCreated);
$stmt->bindParam(":featured", $featured);
$stmt->bindParam(":headerImg", $targetFile["imgLocation"]);
$stmt->bindParam(":body", $newBody);
$stmt->bindParam(":categories", $categories);
if ($stmt->execute())
{
return intval($conn->lastInsertId());
}
return "Error, couldn't create post";
}
}
+43 -2
View File
@@ -12,7 +12,6 @@ use Slim\App;
class blogRoutes implements routesInterface
{
private blogData $blogData;
/**
* constructor used to instantiate a base blog routes, to be used in the index.php file.
* @param App $app - the slim app used to create the routes
@@ -30,6 +29,48 @@ class blogRoutes implements routesInterface
*/
public function createRoutes(App $app): void
{
// TODO: Implement createRoutes() method.
$app->post("/blog/post", function (Request $request, Response $response, array $args)
{
$data = $request->getParsedBody();
$files = $request->getUploadedFiles();
if (empty($data["title"]) || empty($data["body"]) || empty($data["dateCreated"]) || empty($data["featured"]) || empty($data["categories"]) || empty($files["headerImg"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Error, empty data sent")));
return $response->withStatus(400);
}
$insertedID = $this->blogData->createPost($data["title"], $data["body"], $data["dateCreated"], $data["featured"], $data["categories"], $files["headerImg"]);
if (!is_int($insertedID))
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => $insertedID)));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("ID" => $insertedID)));
return $response->withStatus(201);
});
$app->post("/blog/uploadPostImage", function (Request $request, Response $response)
{
$files = $request->getUploadedFiles();
if (empty($files))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => array("message" => "Error, empty data sent"))));
return $response->withStatus(400);
}
$message = $this->blogData->uploadPostImage($files["upload"]);
if (!is_array($message))
{
$response->getBody()->write(json_encode(array("error" => array("message" => $message))));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode($message));
return $response->withStatus(201);
});
}
}
+12 -26
View File
@@ -1,9 +1,11 @@
<?php
namespace api\project;
use api\utils\imgUtils;
use PDO;
use Psr\Http\Message\UploadedFileInterface;
require_once __DIR__ . "/../utils/config.php";
require_once __DIR__ . "/../utils/imgUtils.php";
/**
* Project Data Class
@@ -15,7 +17,7 @@ class projectData
* Get all project data
* @return array - Array of all project data or error message
*/
function getProjectData(): array
public function getProjectData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, title, isMainProject, information, imgLocation, projectLink, gitLink FROM projects ORDER BY isMainProject DESC;");
@@ -43,7 +45,7 @@ class projectData
* @param string $gitLink - Link to the git repository
* @return bool|string - True if project was updated, false if not and there was an error, or an error string
*/
function updateProjectData(string $ID, string $title, string $isMainProject, string $information, string $projectLink, string $gitLink): bool | string
public function updateProjectData(string $ID, string $title, string $isMainProject, string $information, string $projectLink, string $gitLink): bool|string
{
$conn = dbConn();
@@ -82,7 +84,7 @@ class projectData
* @param int $ID - ID of the project in the database to delete
* @return string - True if project was deleted, false if not and there was an error
*/
function deleteProjectData(int $ID): string
public function deleteProjectData(int $ID): string
{
$conn = dbConn();
@@ -121,7 +123,7 @@ class projectData
* @param string $gitLink - Link to the github repository
* @return int|bool - ID of the project if it was added, false if not and there was an error
*/
function addProjectData(string $title, string $isMainProject, string $information, string $projectLink, string $gitLink): int|bool
public function addProjectData(string $title, string $isMainProject, string $information, string $projectLink, string $gitLink): int|bool
{
$conn = dbConn();
@@ -157,31 +159,15 @@ class projectData
public function uploadImage(int $ID, UploadedFileInterface $img): string | array
{
$targetDir = "../imgs/projects/";
$targetFile = $targetDir . basename($img->getClientFilename());
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
$imgUtils = new imgUtils();
$targetFile = $imgUtils->uploadFile($targetDir, $img);
// Check if file already exists
if (file_exists($targetFile))
if (!is_array($targetFile))
{
return "The file already exists";
return $targetFile;
}
// Check file size
if ($img->getSize() > 2000000)
{
return "The file is too large, max 2MB";
}
// Allow certain file formats
if ($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" && $imageFileType != "gif")
{
return "Only JPG, JPEG, PNG & GIF files are allowed";
}
$img->moveTo($targetFile);
if (file_exists($targetFile))
if (file_exists($targetFile["imgLocation"]))
{
$this->deleteImage($ID);
// update the database with the new image location
@@ -193,7 +179,7 @@ class projectData
if ($stmt->rowCount() > 0)
{
return array("imgLocation" => $targetFile);
return array("imgLocation" => $targetFile["imgLocation"]);
}
return "Couldn't update the database";
+3 -3
View File
@@ -113,7 +113,7 @@ class projectRoutes implements routesInterface
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
return $response->withStatus(400)->withStatus(201);
}
$insertedID = $this->projectData->addProjectData($data["title"], $data["isMainProject"], $data["information"], $data["projectLink"], $data["gitLink"]);
@@ -125,7 +125,7 @@ class projectRoutes implements routesInterface
}
$response->getBody()->write(json_encode(array("ID" => $insertedID)));
return $response;
return $response->withStatus(201);
});
$app->post("/projectImage/{id}", function (Request $request, Response $response, array $args)
@@ -147,7 +147,7 @@ class projectRoutes implements routesInterface
}
$response->getBody()->write(json_encode($message));
return $response;
return $response->withStatus(201);
});
}
}
+11 -11
View File
@@ -16,7 +16,7 @@ class timelineData
* Get all education data
* @return array - Array of all education data or error message
*/
function getEduData(): array
public function getEduData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, startPeriod, endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
@@ -24,7 +24,7 @@ class timelineData
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
@@ -36,7 +36,7 @@ class timelineData
* Get all work data
* @return array - Array of all work data or error message
*/
function getWorkData(): array
public function getWorkData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
@@ -61,7 +61,7 @@ class timelineData
* @param string $id - ID of the education data
* @return bool - True if successful, false if not
*/
function updateEduData(string $dateFrom, string $dateTo, string $grade, string $course, string $id): bool
public function updateEduData(string $dateFrom, string $dateTo, string $grade, string $course, string $id): bool
{
$conn = dbConn();
$stmt = $conn->prepare("UPDATE edu SET startPeriod = :dateFrom, endPeriod = :dateTo, grade = :grade, course = :course WHERE ID = :id;");
@@ -101,7 +101,7 @@ class timelineData
* @param int $id
* @return bool - True if successful, false if not
*/
function deleteEduData(int $id): bool
public function deleteEduData(int $id): bool
{
$conn = dbConn();
$stmt = $conn->prepare("DELETE FROM edu WHERE ID = :id;");
@@ -130,7 +130,7 @@ class timelineData
* @param string $course - Course
* @return bool|int - ID of the new education data or false if not successful
*/
function addEduData(string $dateFrom, string $dateTo, string $grade, string $course): bool|int
public function addEduData(string $dateFrom, string $dateTo, string $grade, string $course): bool|int
{
$conn = dbConn();
$stmt = $conn->prepare("INSERT INTO edu (startPeriod, endPeriod, grade, course) VALUES (:dateFrom, :dateTo, :grade, :course);");
@@ -138,8 +138,8 @@ class timelineData
$stmt->bindParam(":dateTo", $dateTo);
$stmt->bindParam(":grade", $grade);
$stmt->bindParam(":course", $course);
if($stmt->execute())
if ($stmt->execute())
{
return $conn->lastInsertId();
}
@@ -155,7 +155,7 @@ class timelineData
* @param string $title - Title
* @return bool|int - ID of the new work data if successful, false if not
*/
function addWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title): bool|int
public function addWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title): bool|int
{
$conn = dbConn();
$stmt = $conn->prepare("INSERT INTO work (startPeriod, endPeriod, companyName, area, title) VALUES (:dateFrom, :dateTo, :companyName, :area, :title);");
@@ -164,8 +164,8 @@ class timelineData
$stmt->bindParam(":companyName", $companyName);
$stmt->bindParam(":area", $area);
$stmt->bindParam(":title", $title);
if($stmt->execute())
if ($stmt->execute())
{
return $conn->lastInsertId();
}
+13 -13
View File
@@ -17,16 +17,16 @@ class userData
* @param $password string - Password
* @return bool - True if logged in, false if not
*/
function checkUser(string $username, string $password): bool
public function checkUser(string $username, string $password): bool
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
$stmt->bindParam(":username", $username);
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
if (password_verify($password, $result[0]["password"]))
@@ -43,15 +43,15 @@ class userData
* @param $username string - Username
* @return string - JWT token
*/
function createToken(string $username): string
public function createToken(string $username): string
{
$now = time();
$future = strtotime('+6 hour',$now);
$future = strtotime('+6 hour', $now);
$secretKey = getSecretKey();
$payload = [
"jti"=>$username,
"iat"=>$now,
"exp"=>$future
"jti" => $username,
"iat" => $now,
"exp" => $future
];
return JWT::encode($payload,$secretKey,"HS256");
@@ -62,7 +62,7 @@ class userData
* @param string $email - Email to check
* @return bool - True if email exists, false if not
*/
function checkEmail(string $email): bool
public function checkEmail(string $email): bool
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
@@ -84,14 +84,14 @@ class userData
* @param $email - email address of the userData
* @return string - verification code
*/
function sendResetEmail($email): string
public function sendResetEmail($email): string
{
//generate a random token and email the address
$token = uniqid("rpe-");
$headers1 = "From: noreply@rohitpai.co.uk\r\n";
$headers1 .= "MIME-Version: 1.0\r\n";
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
$message = "
<!doctype html>
<html lang='en'>
@@ -119,14 +119,14 @@ class userData
* @param $password string Password
* @return bool - true if the password was changed, false if not
*/
function changePassword(string $email, string $password): bool
public function changePassword(string $email, string $password): bool
{
$conn = dbConn();
$stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email");
$newPwd = password_hash($password, PASSWORD_BCRYPT);
$stmt->bindParam(":password", $newPwd);
$stmt->bindParam(":email", $email);
if ($stmt->execute())
{
return true;
+1 -1
View File
@@ -145,7 +145,7 @@ class userRoutes implements routesInterface
// yay, password changed
unset($_SESSION["resetToken"]);
unset($_SESSION["resetEmail"]);
return $response;
return $response->withStatus(201);
}
return $response->withStatus(500);
+12 -8
View File
@@ -27,7 +27,7 @@ class middleware
* Constructor for middleware
* @param App $app - Slim App
*/
function __construct(App $app)
public function __construct(App $app)
{
$this->baseMiddleware($app);
$this->sameSiteConfig($app);
@@ -40,7 +40,7 @@ class middleware
* Base middleware
* @param App $app - Slim App
*/
function baseMiddleware(App $app): void
public function baseMiddleware(App $app): void
{
$app->addBodyParsingMiddleware();
$app->addRoutingMiddleware();
@@ -50,7 +50,7 @@ class middleware
* SameSite Cookie Configuration
* @param App $app - Slim App
*/
function sameSiteConfig(App $app): void
public function sameSiteConfig(App $app): void
{
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
$app->add(new SameSiteCookieMiddleware($ssConfig));
@@ -60,7 +60,7 @@ class middleware
* Return all responses as JSON
* @param App $app - Slim App
*/
function returnAsJSON(App $app): void
public function returnAsJSON(App $app): void
{
$app->add(function ($request, $handler)
{
@@ -73,7 +73,7 @@ class middleware
* JWT Authentication
* @param App $app - Slim App
*/
function jwtAuth(App $app): void
public function jwtAuth(App $app): void
{
$jwtSecret = getSecretKey();
$app->add(new JwtAuthentication([
@@ -90,14 +90,18 @@ class middleware
"error" => function ($response)
{
session_destroy();
$response->getBody()->write(json_encode(array("status" => "401", "message" =>
"Unauthorized, please provide a valid token")));
$response->getBody()->write(json_encode(array("status" => "401", "message" =>
"Unauthorized, please provide a valid token")));
return $response->withStatus(401);
}
]));
}
function errorHandling(App $app): void
/**
* Error handling
* @param App $app - Slim App
*/
public function errorHandling(App $app): void
{
$app->add(function (ServerRequestInterface $request, RequestHandlerInterface $handler)
{