diff --git a/classes/Ijdb/Controllers/Category.php b/classes/Ijdb/Controllers/Category.php new file mode 100644 index 0000000..072d11e --- /dev/null +++ b/classes/Ijdb/Controllers/Category.php @@ -0,0 +1,53 @@ +categoriesTable = $categoriesTable; + } + + public function edit() { + + if (isset($_GET['id'])) { + $category = $this->categoriesTable->findById($_GET['id']); + } + + $title = 'Edit Category'; + + return ['template' => 'editcategory.html.php', + 'title' => $title, + 'variables' => [ + 'category' => $category ?? null + ] + ]; + } + + public function saveEdit() { + $category = $_POST['category']; + + $this->categoriesTable->save($category); + + header('location: /category/list'); + } + + public function list() { + $categories = $this->categoriesTable->findAll(); + + $title = 'Joke Categories'; + + return ['template' => 'categories.html.php', + 'title' => $title, + 'variables' => [ + 'categories' => $categories + ] + ]; + } + + public function delete() { + $this->categoriesTable->delete($_POST['id']); + + header('location: /category/list'); + } +} \ No newline at end of file diff --git a/classes/Ijdb/Controllers/Joke.php b/classes/Ijdb/Controllers/Joke.php new file mode 100644 index 0000000..edc8068 --- /dev/null +++ b/classes/Ijdb/Controllers/Joke.php @@ -0,0 +1,113 @@ +jokesTable = $jokesTable; + $this->authorsTable = $authorsTable; + $this->categoriesTable = $categoriesTable; + $this->authentication = $authentication; + } + + public function list() { + + $page = $_GET['page'] ?? 1; + + $offset = ($page-1)*10; + + if (isset($_GET['category'])) { + $category = $this->categoriesTable->findById($_GET['category']); + $jokes = $category->getJokes(10, $offset); + $totalJokes = $category->getNumJokes(); + } + else { + $jokes = $this->jokesTable->findAll('jokedate DESC', 10, $offset); + $totalJokes = $this->jokesTable->total(); + } + + $title = 'Joke list'; + + + + $author = $this->authentication->getUser(); + + return ['template' => 'jokes.html.php', + 'title' => $title, + 'variables' => [ + 'totalJokes' => $totalJokes, + 'jokes' => $jokes, + 'user' => $author, + 'categories' => $this->categoriesTable->findAll(), + 'currentPage' => $page, + 'categoryId' => $_GET['category'] ?? null + ] + ]; + } + + public function home() { + $title = 'Internet Joke Database'; + + return ['template' => 'home.html.php', 'title' => $title]; + } + + public function delete() { + + $author = $this->authentication->getUser(); + + $joke = $this->jokesTable->findById($_POST['id']); + + if ($joke->authorId != $author->id && !$author->hasPermission(\Ijdb\Entity\Author::DELETE_JOKES) ) { + return; + } + + + $this->jokesTable->delete($_POST['id']); + + header('location: /joke/list'); + } + + public function saveEdit() { + $author = $this->authentication->getUser(); + + $joke = $_POST['joke']; + $joke['jokedate'] = new \DateTime(); + + $jokeEntity = $author->addJoke($joke); + + $jokeEntity->clearCategories(); + + foreach ($_POST['category'] as $categoryId) { + $jokeEntity->addCategory($categoryId); + } + + header('location: /joke/list'); + } + + public function edit() { + $author = $this->authentication->getUser(); + $categories = $this->categoriesTable->findAll(); + + if (isset($_GET['id'])) { + $joke = $this->jokesTable->findById($_GET['id']); + } + + $title = 'Edit joke'; + + return ['template' => 'editjoke.html.php', + 'title' => $title, + 'variables' => [ + 'joke' => $joke ?? null, + 'user' => $author, + 'categories' => $categories + ] + ]; + } + +} \ No newline at end of file diff --git a/classes/Ijdb/Controllers/Login.php b/classes/Ijdb/Controllers/Login.php new file mode 100644 index 0000000..6a336cb --- /dev/null +++ b/classes/Ijdb/Controllers/Login.php @@ -0,0 +1,46 @@ +authentication = $authentication; + } + + public function loginForm() { + return ['template' => 'login.html.php', 'title' => 'Log In']; + } + + public function processLogin() { + if ($this->authentication->login($_POST['email'], $_POST['password'])) { + header('location: /login/success'); + } + else { + return ['template' => 'login.html.php', + 'title' => 'Log In', + 'variables' => [ + 'error' => 'Invalid username/password.' + ] + ]; + } + } + + public function success() { + return ['template' => 'loginsuccess.html.php', 'title' => 'Login Successful']; + } + + public function error() { + return ['template' => 'loginerror.html.php', 'title' => 'You are not logged in']; + } + + public function permissionsError() { + return ['template' => 'permissionserror.html.php', 'title' => 'Access Denied']; + } + + public function logout() { + unset($_SESSION); + session_destroy(); + return ['template' => 'logout.html.php', 'title' => 'You have been logged out']; + } +} diff --git a/classes/Ijdb/Controllers/Register.php b/classes/Ijdb/Controllers/Register.php new file mode 100644 index 0000000..e665002 --- /dev/null +++ b/classes/Ijdb/Controllers/Register.php @@ -0,0 +1,121 @@ +authorsTable = $authorsTable; + } + + public function registrationForm() { + return ['template' => 'register.html.php', + 'title' => 'Register an account']; + } + + + public function success() { + return ['template' => 'registersuccess.html.php', + 'title' => 'Registration Successful']; + } + + public function registerUser() { + $author = $_POST['author']; + + //Assume the data is valid to begin with + $valid = true; + $errors = []; + + //But if any of the fields have been left blank, set $valid to false + if (empty($author['name'])) { + $valid = false; + $errors[] = 'Name cannot be blank'; + } + + if (empty($author['email'])) { + $valid = false; + $errors[] = 'Email cannot be blank'; + } + else if (filter_var($author['email'], FILTER_VALIDATE_EMAIL) == false) { + $valid = false; + $errors[] = 'Invalid email address'; + } + else { //if the email is not blank and valid: + //convert the email to lowercase + $author['email'] = strtolower($author['email']); + + //search for the lowercase version of `$author['email']` + if (count($this->authorsTable->find('email', $author['email'])) > 0) { + $valid = false; + $errors[] = 'That email address is already registered'; + } + } + + + if (empty($author['password'])) { + $valid = false; + $errors[] = 'Password cannot be blank'; + } + + //If $valid is still true, no fields were blank and the data can be added + if ($valid == true) { + //Hash the password before saving it in the database + $author['password'] = password_hash($author['password'], PASSWORD_DEFAULT); + + //When submitted, the $author variable now contains a lowercase value for email + //and a hashed password + $this->authorsTable->save($author); + + header('Location: /author/success'); + } + else { + //If the data is not valid, show the form again + return ['template' => 'register.html.php', + 'title' => 'Register an account', + 'variables' => [ + 'errors' => $errors, + 'author' => $author + ] + ]; + } + } + + public function list() { + $authors = $this->authorsTable->findAll(); + + return ['template' => 'authorlist.html.php', + 'title' => 'Author List', + 'variables' => [ + 'authors' => $authors + ] + ]; + } + + public function permissions() { + + $author = $this->authorsTable->findById($_GET['id']); + + $reflected = new \ReflectionClass('\Ijdb\Entity\Author'); + $constants = $reflected->getConstants(); + + return ['template' => 'permissions.html.php', + 'title' => 'Edit Permissions', + 'variables' => [ + 'author' => $author, + 'permissions' => $constants + ] + ]; + } + + public function savePermissions() { + $author = [ + 'id' => $_GET['id'], + 'permissions' => array_sum($_POST['permissions'] ?? []) + ]; + + $this->authorsTable->save($author); + + header('location: /author/list'); + } +} \ No newline at end of file diff --git a/classes/Ijdb/Entity/Author.php b/classes/Ijdb/Entity/Author.php new file mode 100644 index 0000000..2d82f69 --- /dev/null +++ b/classes/Ijdb/Entity/Author.php @@ -0,0 +1,36 @@ +jokesTable = $jokeTable; + } + + public function getJokes() { + return $this->jokesTable->find('authorId', $this->id); + } + + public function addJoke($joke) { + $joke['authorId'] = $this->id; + + return $this->jokesTable->save($joke); + } + + public function hasPermission($permission) { + return $this->permissions & $permission; + } +} \ No newline at end of file diff --git a/classes/Ijdb/Entity/Category.php b/classes/Ijdb/Entity/Category.php new file mode 100644 index 0000000..9e1f3c5 --- /dev/null +++ b/classes/Ijdb/Entity/Category.php @@ -0,0 +1,48 @@ +jokesTable = $jokesTable; + $this->jokeCategoriesTable = $jokeCategoriesTable; + } + + public function getJokes($limit = null, $offset = null) { + $jokeCategories = $this->jokeCategoriesTable->find('categoryId', $this->id, null, $limit, $offset); + + $jokes = []; + + foreach ($jokeCategories as $jokeCategory) { + $joke = $this->jokesTable->findById($jokeCategory->jokeId); + if ($joke) { + $jokes[] = $joke; + } + } + + usort($jokes, [$this, 'sortJokes']); + + return $jokes; + } + + public function getNumJokes() { + return $this->jokeCategoriesTable->total('categoryId', $this->id); + } + + private function sortJokes($a, $b) { + $aDate = new \DateTime($a->jokedate); + $bDate = new \DateTime($b->jokedate); + + if ($aDate->getTimestamp() == $bDate->getTimestamp()) { + return 0; + } + + return $aDate->getTimestamp() < $bDate->getTimestamp() ? -1 : 1; + } +} \ No newline at end of file diff --git a/classes/Ijdb/Entity/Joke.php b/classes/Ijdb/Entity/Joke.php new file mode 100644 index 0000000..2ddc8e5 --- /dev/null +++ b/classes/Ijdb/Entity/Joke.php @@ -0,0 +1,45 @@ +authorsTable = $authorsTable; + $this->jokeCategoriesTable = $jokeCategoriesTable; + } + + public function getAuthor() { + if (empty($this->author)) { + $this->author = $this->authorsTable->findById($this->authorId); + } + + return $this->author; + } + + public function addCategory($categoryId) { + $jokeCat = ['jokeId' => $this->id, 'categoryId' => $categoryId]; + + $this->jokeCategoriesTable->save($jokeCat); + } + + public function hasCategory($categoryId) { + $jokeCategories = $this->jokeCategoriesTable->find('jokeId', $this->id); + + foreach ($jokeCategories as $jokeCategory) { + if ($jokeCategory->categoryId == $categoryId) { + return true; + } + } + } + + public function clearCategories() { + $this->jokeCategoriesTable->deleteWhere('jokeId', $this->id); + } +} \ No newline at end of file diff --git a/classes/Ijdb/IjdbRoutes.php b/classes/Ijdb/IjdbRoutes.php new file mode 100644 index 0000000..c3a106e --- /dev/null +++ b/classes/Ijdb/IjdbRoutes.php @@ -0,0 +1,175 @@ +jokesTable = new \Ninja\DatabaseTable($pdo, 'joke', 'id', '\Ijdb\Entity\Joke', [&$this->authorsTable, &$this->jokeCategoriesTable]); + $this->authorsTable = new \Ninja\DatabaseTable($pdo, 'author', 'id', '\Ijdb\Entity\Author', [&$this->jokesTable]); + $this->categoriesTable = new \Ninja\DatabaseTable($pdo, 'category', 'id', '\Ijdb\Entity\Category', [&$this->jokesTable, &$this->jokeCategoriesTable]); + $this->jokeCategoriesTable = new \Ninja\DatabaseTable($pdo, 'joke_category', 'categoryId'); + $this->authentication = new \Ninja\Authentication($this->authorsTable, 'email', 'password'); + } + + public function getRoutes(): array { + $jokeController = new \Ijdb\Controllers\Joke($this->jokesTable, $this->authorsTable, $this->categoriesTable, $this->authentication); + $authorController = new \Ijdb\Controllers\Register($this->authorsTable); + $loginController = new \Ijdb\Controllers\Login($this->authentication); + $categoryController = new \Ijdb\Controllers\Category($this->categoriesTable); + + $routes = [ + 'author/register' => [ + 'GET' => [ + 'controller' => $authorController, + 'action' => 'registrationForm' + ], + 'POST' => [ + 'controller' => $authorController, + 'action' => 'registerUser' + ] + ], + 'author/success' => [ + 'GET' => [ + 'controller' => $authorController, + 'action' => 'success' + ] + ], + 'author/permissions' => [ + 'GET' => [ + 'controller' => $authorController, + 'action' => 'permissions' + ], + 'POST' => [ + 'controller' => $authorController, + 'action' => 'savePermissions' + ], + 'login' => true, + 'permissions' => \Ijdb\Entity\Author::EDIT_USER_ACCESS + ], + 'author/list' => [ + 'GET' => [ + 'controller' => $authorController, + 'action' => 'list' + ], + 'login' => true, + 'permissions' => \Ijdb\Entity\Author::EDIT_USER_ACCESS + ], + 'joke/edit' => [ + 'POST' => [ + 'controller' => $jokeController, + 'action' => 'saveEdit' + ], + 'GET' => [ + 'controller' => $jokeController, + 'action' => 'edit' + ], + 'login' => true + ], + 'joke/delete' => [ + 'POST' => [ + 'controller' => $jokeController, + 'action' => 'delete' + ], + 'login' => true + ], + 'joke/list' => [ + 'GET' => [ + 'controller' => $jokeController, + 'action' => 'list' + ] + ], + 'login/error' => [ + 'GET' => [ + 'controller' => $loginController, + 'action' => 'error' + ] + ], + 'login/permissionserror' => [ + 'GET' => [ + 'controller' => $loginController, + 'action' => 'permissionsError' + ] + ], + 'login/success' => [ + 'GET' => [ + 'controller' => $loginController, + 'action' => 'success' + ] + ], + 'logout' => [ + 'GET' => [ + 'controller' => $loginController, + 'action' => 'logout' + ] + ], + 'login' => [ + 'GET' => [ + 'controller' => $loginController, + 'action' => 'loginForm' + ], + 'POST' => [ + 'controller' => $loginController, + 'action' => 'processLogin' + ] + ], + 'category/edit' => [ + 'POST' => [ + 'controller' => $categoryController, + 'action' => 'saveEdit' + ], + 'GET' => [ + 'controller' => $categoryController, + 'action' => 'edit' + ], + 'login' => true, + 'permissions' => \Ijdb\Entity\Author::EDIT_CATEGORIES + ], + 'category/delete' => [ + 'POST' => [ + 'controller' => $categoryController, + 'action' => 'delete' + ], + 'login' => true, + 'permissions' => \Ijdb\Entity\Author::REMOVE_CATEGORIES + ], + 'category/list' => [ + 'GET' => [ + 'controller' => $categoryController, + 'action' => 'list' + ], + 'login' => true, + 'permissions' => \Ijdb\Entity\Author::EDIT_CATEGORIES + ], + '' => [ + 'GET' => [ + 'controller' => $jokeController, + 'action' => 'home' + ] + ] + ]; + + return $routes; + } + + public function getAuthentication(): \Ninja\Authentication { + return $this->authentication; + } + + public function checkPermission($permission): bool { + $user = $this->authentication->getUser(); + + if ($user && $user->hasPermission($permission)) { + return true; + } else { + return false; + } + } + +} \ No newline at end of file diff --git a/classes/Ninja/Authentication.php b/classes/Ninja/Authentication.php new file mode 100644 index 0000000..5ee838c --- /dev/null +++ b/classes/Ninja/Authentication.php @@ -0,0 +1,53 @@ +users = $users; + $this->usernameColumn = $usernameColumn; + $this->passwordColumn = $passwordColumn; + } + + public function login($username, $password) { + $user = $this->users->find($this->usernameColumn, strtolower($username)); + + if (!empty($user) && password_verify($password, $user[0]->{$this->passwordColumn})) { + session_regenerate_id(); + $_SESSION['username'] = $username; + $_SESSION['password'] = $user[0]->{$this->passwordColumn}; + return true; + } + else { + return false; + } + } + + public function isLoggedIn() { + if (empty($_SESSION['username'])) { + return false; + } + + $user = $this->users->find($this->usernameColumn, strtolower($_SESSION['username'])); + + if (!empty($user) && $user[0]->{$this->passwordColumn} === $_SESSION['password']) { + return true; + } + else { + return false; + } + } + + public function getUser() { + if ($this->isLoggedIn()) { + return $this->users->find($this->usernameColumn, strtolower($_SESSION['username']))[0]; + } + else { + return false; + } + } +} \ No newline at end of file diff --git a/classes/Ninja/DatabaseTable.php b/classes/Ninja/DatabaseTable.php new file mode 100644 index 0000000..747a143 --- /dev/null +++ b/classes/Ninja/DatabaseTable.php @@ -0,0 +1,193 @@ +pdo = $pdo; + $this->table = $table; + $this->primaryKey = $primaryKey; + $this->className = $className; + $this->constructorArgs = $constructorArgs; + } + + private function query($sql, $parameters = []) { + $query = $this->pdo->prepare($sql); + $query->execute($parameters); + return $query; + } + + public function total($field = null, $value = null) { + $sql = 'SELECT COUNT(*) FROM `' . $this->table . '`'; + $parameters = []; + + if (!empty($field)) { + $sql .= ' WHERE `' . $field . '` = :value'; + $parameters = ['value' => $value]; + } + + $query = $this->query($sql, $parameters); + $row = $query->fetch(); + return $row[0]; + } + + public function findById($value) { + $query = 'SELECT * FROM `' . $this->table . '` WHERE `' . $this->primaryKey . '` = :value'; + + $parameters = [ + 'value' => $value + ]; + + $query = $this->query($query, $parameters); + + return $query->fetchObject($this->className, $this->constructorArgs); + } + + public function find($column, $value, $orderBy = null, $limit = null, $offset = null) { + $query = 'SELECT * FROM ' . $this->table . ' WHERE ' . $column . ' = :value'; + + $parameters = [ + 'value' => $value + ]; + + if ($orderBy != null) { + $query .= ' ORDER BY ' . $orderBy; + } + + if ($limit != null) { + $query .= ' LIMIT ' . $limit; + } + + if ($offset != null) { + $query .= ' OFFSET ' . $offset; + } + + $query = $this->query($query, $parameters); + + return $query->fetchAll(\PDO::FETCH_CLASS, $this->className, $this->constructorArgs); + } + + private function insert($fields) { + $query = 'INSERT INTO `' . $this->table . '` ('; + + foreach ($fields as $key => $value) { + $query .= '`' . $key . '`,'; + } + + $query = rtrim($query, ','); + + $query .= ') VALUES ('; + + + foreach ($fields as $key => $value) { + $query .= ':' . $key . ','; + } + + $query = rtrim($query, ','); + + $query .= ')'; + + $fields = $this->processDates($fields); + + $this->query($query, $fields); + + return $this->pdo->lastInsertId(); + } + + + private function update($fields) { + $query = ' UPDATE `' . $this->table .'` SET '; + + foreach ($fields as $key => $value) { + $query .= '`' . $key . '` = :' . $key . ','; + } + + $query = rtrim($query, ','); + + $query .= ' WHERE `' . $this->primaryKey . '` = :primaryKey'; + + //Set the :primaryKey variable + $fields['primaryKey'] = $fields[$this->primaryKey]; + + $fields = $this->processDates($fields); + + $this->query($query, $fields); + } + + + public function delete($id) { + $parameters = [':id' => $id]; + + $this->query('DELETE FROM `' . $this->table . '` WHERE `' . $this->primaryKey . '` = :id', $parameters); + } + + public function deleteWhere($column, $value) { + $query = 'DELETE FROM ' . $this->table . ' WHERE ' . $column . ' = :value'; + + $parameters = [ + 'value' => $value + ]; + + $query = $this->query($query, $parameters); + } + + public function findAll($orderBy = null, $limit = null, $offset = null) { + $query = 'SELECT * FROM ' . $this->table; + + if ($orderBy != null) { + $query .= ' ORDER BY ' . $orderBy; + } + + if ($limit != null) { + $query .= ' LIMIT ' . $limit; + } + + if ($offset != null) { + $query .= ' OFFSET ' . $offset; + } + + $result = $this->query($query); + + return $result->fetchAll(\PDO::FETCH_CLASS, $this->className, $this->constructorArgs); + } + + private function processDates($fields) { + foreach ($fields as $key => $value) { + if ($value instanceof \DateTime) { + $fields[$key] = $value->format('Y-m-d'); + } + } + + return $fields; + } + + + public function save($record) { + $entity = new $this->className(...$this->constructorArgs); + + try { + if ($record[$this->primaryKey] == '') { + $record[$this->primaryKey] = null; + } + $insertId = $this->insert($record); + + $entity->{$this->primaryKey} = $insertId; + } + catch (\PDOException $e) { + $this->update($record); + } + + foreach ($record as $key => $value) { + if (!empty($value)) { + $entity->$key = $value; + } + } + + return $entity; + } +} \ No newline at end of file diff --git a/classes/Ninja/EntryPoint.php b/classes/Ninja/EntryPoint.php new file mode 100644 index 0000000..3f6da7b --- /dev/null +++ b/classes/Ninja/EntryPoint.php @@ -0,0 +1,66 @@ +route = $route; + $this->routes = $routes; + $this->method = $method; + $this->checkUrl(); + } + + private function checkUrl() { + if ($this->route !== strtolower($this->route)) { + http_response_code(301); + header('location: ' . strtolower($this->route)); + } + } + + private function loadTemplate($templateFileName, $variables = []) { + extract($variables); + + ob_start(); + include __DIR__ . '/../../templates/' . $templateFileName; + + return ob_get_clean(); + } + + public function run() { + + $routes = $this->routes->getRoutes(); + + $authentication = $this->routes->getAuthentication(); + + if (isset($routes[$this->route]['login']) && !$authentication->isLoggedIn()) { + header('location: /login/error'); + } + else if (isset($routes[$this->route]['permissions']) && !$this->routes->checkPermission($routes[$this->route]['permissions'])) { + header('location: /login/permissionserror'); + } + else { + $controller = $routes[$this->route][$this->method]['controller']; + $action = $routes[$this->route][$this->method]['action']; + $page = $controller->$action(); + + $title = $page['title']; + + if (isset($page['variables'])) { + $output = $this->loadTemplate($page['template'], $page['variables']); + } + else { + $output = $this->loadTemplate($page['template']); + } + + echo $this->loadTemplate('layout.html.php', ['loggedIn' => $authentication->isLoggedIn(), + 'output' => $output, + 'title' => $title + ]); + + } + + } +} \ No newline at end of file diff --git a/classes/Ninja/Markdown.php b/classes/Ninja/Markdown.php new file mode 100644 index 0000000..9df4ad6 --- /dev/null +++ b/classes/Ninja/Markdown.php @@ -0,0 +1,40 @@ +string = $markDown; + } + + public function toHtml() { + //convert $this->string to HTML + $text = htmlspecialchars($this->string, ENT_QUOTES, 'UTF-8'); + + // strong (bold) + $text = preg_replace('/__(.+?)__/s', '$1', $text); + $text = preg_replace('/\*\*(.+?)\*\*/s', '$1', $text); + + // emphasis (italic) + $text = preg_replace('/_([^_]+)_/', '$1', $text); + $text = preg_replace('/\*([^\*]+)\*/', '$1', $text); + + // Convert Windows (\r\n) to Unix (\n) + $text = str_replace("\r\n", "\n", $text); + // Convert Macintosh (\r) to Unix (\n) + $text = str_replace("\r", "\n", $text); + + // Paragraphs + $text = '

' . str_replace("\n\n", '

', $text) . '

'; + // Line breaks + $text = str_replace("\n", '
', $text); + + // [linked text](link URL) + $text = preg_replace( + '/\[([^\]]+)]\(([-a-z0-9._~:\/?#@!$&\'()*+,;=%]+)\)/i', + '$1', $text); + + return $text; + } +} \ No newline at end of file diff --git a/classes/Ninja/Routes.php b/classes/Ninja/Routes.php new file mode 100644 index 0000000..c309fdf --- /dev/null +++ b/classes/Ninja/Routes.php @@ -0,0 +1,8 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); \ No newline at end of file diff --git a/includes/autoload.php b/includes/autoload.php new file mode 100644 index 0000000..23a2652 --- /dev/null +++ b/includes/autoload.php @@ -0,0 +1,10 @@ +run(); +} +catch (PDOException $e) { + $title = 'An error has occurred'; + + $output = 'Database error: ' . $e->getMessage() . ' in ' . + $e->getFile() . ':' . $e->getLine(); + + include __DIR__ . '/../templates/layout.html.php'; +} diff --git a/public/jokes.css b/public/jokes.css new file mode 100644 index 0000000..c0b9b0b --- /dev/null +++ b/public/jokes.css @@ -0,0 +1,43 @@ + * {margin: 0; padding: 0; } +body {font-family: Arial, Helvetica, Sans-serif; } +header {display: block; background-color: #3cbc8d; padding: 20px; border-bottom: 5px solid #757575;} +h1 {font-weight: normal; padding: 1.5em; color: white; text-shadow: 1px 1px 0px #444; width: 1000px; margin: auto;} + +nav {background-color: #443A5C;} + +nav a {color: white; text-decoration: none;} +nav a:hover {color: #ddd;} +nav ul {display: table; width: 1000px; margin: auto;} +nav li {display: table-cell; text-align: center; padding: 1em;} + +main {overflow: auto; min-height: 30vh; background-color: #f7f7f7; width: 1000px; margin: auto; box-shadow: -1000px 0 0 #f7f7f7, 1000px 0 0 #f7f7f7; padding-top: 20px;} + +footer {padding: 1em; background-color: #FFC9A7 ; font-size: 0.8em;} + +p {margin-bottom: 1em;} + +body {font-size: 1.2em; font-family: arial, helvetica, sans-serif} +input, label, select, textarea {float: left; width: 15em; margin-bottom: 1em; padding: 0.5em;} +label {clear: left; padding: 0; margin: 0;} +input[type="submit"] {margin-left: 15em; width: auto; padding: 0.5em 1em; clear: both; font-size: 1em;} +form {overflow: auto; clear: both; display: block;} + +blockquote {display: table; margin-bottom: 1em; border-bottom: 1px solid #ccc; padding: 0.5em; } +blockquote p {display: table-cell; width: 70%; vertical-align: top;} +blockquote form { display: table-cell; width: 10%;} + +.errors {padding: 1em; border: 1px solid red; background-color: lightyellow; color: red; margin-bottom: 1em; overflow: auto;} +.errors ul {margin-left: 1em;} + +form p {clear: both;} +input[type="checkbox"] {float: left; clear: left; width: auto; margin-right: 10px;} +input[type="checkbox"] + label {clear: right;} + +.jokelist {display: table;} +.categories {display: table-cell; width: 20%; background-color: #333; padding: 1em; list-style-type: none;} +.categories a {color: white; text-decoration: none;} +.categories li {margin-bottom: 1em;} +.jokelist .jokes {display: table-cell; padding: 1em;} + +.currentpage:before { content: "["; } +.currentpage:after { content: "]"; } \ No newline at end of file diff --git a/public/samples/index.php b/public/samples/index.php new file mode 100644 index 0000000..a3dc2d4 --- /dev/null +++ b/public/samples/index.php @@ -0,0 +1,164 @@ + +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +} +catch (PDOException $e) { + echo '

Could not connect to database. Did you delete the `homestead` user or change it\'s password?

'; + echo '

' . $e . '

'; + die; +} + + +try { + //sample user might not exist so the query may throw an exception, that's fine, ignore it. + try { + //Drop the user, there's a chance the password has been changed + $pdo->query('DROP USER \'ijdb_sample\'@\'localhost\''); + } + catch (PDOException $e) {} + + //Create the user for the sample code to use + $pdo->query('CREATE USER \'ijdb_sample\'@\'localhost\' IDENTIFIED BY \'mypassword\''); + + //Drop the database, only one sample should be used at once. + + $pdo->query('DROP DATABASE IF EXISTS ijdb_sample'); + + + $pdo->query('CREATE DATABASE ijdb_sample'); + $pdo->query('GRANT ALL PRIVILEGES ON ijdb_sample.* To \'ijdb_sample\'@\'localhost\''); + $pdo->query('FLUSH PRIVILEGES'); + $pdo->query('USE ijdb_sample'); + + if (file_exists('../../database.sql')) { + $pdo->exec(file_get_contents('../../database.sql')); + } + +} +catch (PDOException $e) { + echo 'Could not create sample database/user'; + echo $e->getMessage(); +} + + +exec('git status', $output); +$branchName = str_replace('On branch ', '', $output[0]); + +if (isset($_GET['branch'])) { + exec('git status', $status); + $status = implode("\n", $status); + if (strpos($status, 'nothing to commit') == false) { + + + + $parts = explode('_Modified', $branchName); + $newBranchName = $parts[0] . '_Modified-' . date('Y-m-d-H.i.s'); + + + exec('git checkout -b ' . $newBranchName . ' 2>&1', $z); + + exec('git add -A 2>&1', $x); + exec('git commit -m "user modified sample" 2>&1', $y); + + var_dump($z); + var_dump($y); + var_dump($x); + } + exec('git checkout "' . $_GET['branch'] . '"', $n); + $branchName = $_GET['branch']; +} + +if (!isset($branchName)) { + exec('git status', $output); + $branchName = str_replace('On branch ', '', $output[0]); +} + + +?> + + + <?= $branchName; ?> - PHP Nove to Ninja sample code + + + + + + + + +

PHP Novice to Ninja sample code

+ +

Click on a file to view in your browser

+ + + + +

View a different sample

+ + + + diff --git a/templates/authorlist.html.php b/templates/authorlist.html.php new file mode 100644 index 0000000..7e72e8b --- /dev/null +++ b/templates/authorlist.html.php @@ -0,0 +1,21 @@ +

User List

+ + + + + + + + + + + + + + + + + +
NameEmailEdit
name;?>email;?>Edit Permissions
+ + diff --git a/templates/categories.html.php b/templates/categories.html.php new file mode 100644 index 0000000..338dfd2 --- /dev/null +++ b/templates/categories.html.php @@ -0,0 +1,20 @@ + +

Categories

+ +Add a new category + + + +
+

+ name, ENT_QUOTES, 'UTF-8')?> + + Edit +

+ + +
+

+
+ + diff --git a/templates/editcategory.html.php b/templates/editcategory.html.php new file mode 100644 index 0000000..b88cb3f --- /dev/null +++ b/templates/editcategory.html.php @@ -0,0 +1,6 @@ +
+ + + + +
diff --git a/templates/editjoke.html.php b/templates/editjoke.html.php new file mode 100644 index 0000000..b24b563 --- /dev/null +++ b/templates/editjoke.html.php @@ -0,0 +1,25 @@ +id) || $user->id == $joke->authorId || $user->hasPermission(\Ijdb\Entity\Author::EDIT_JOKES)): ?> +
+ + + + +

Select categories for this joke:

+ + + hasCategory($category->id)): ?> + + + + + + + + + +
+ + +

You may only edit jokes that you posted.

+ + \ No newline at end of file diff --git a/templates/home.html.php b/templates/home.html.php new file mode 100644 index 0000000..d143cf0 --- /dev/null +++ b/templates/home.html.php @@ -0,0 +1,3 @@ +

Internet Joke Database

+ +

Welcome to the Internet Joke Database

\ No newline at end of file diff --git a/templates/jokes.html.php b/templates/jokes.html.php new file mode 100644 index 0000000..428f337 --- /dev/null +++ b/templates/jokes.html.php @@ -0,0 +1,59 @@ +
+ + + +
+ +

jokes have been submitted to the Internet Joke Database.

+ + + +
+ joketext))->toHtml()?> + + (by + getAuthor()->name, ENT_QUOTES, + 'UTF-8'); ?> on +jokedate); + +echo $date->format('jS F Y'); +?>) + + + id == $joke->authorId || $user->hasPermission(\Ijdb\Entity\Author::EDIT_JOKES)): ?> + Edit + + id == $joke->authorId || $user->hasPermission(\Ijdb\Entity\Author::DELETE_JOKES)): ?> +
+ + +
+ + +
+ + + + +Select page: + + + + + + + + +
diff --git a/templates/layout.html.php b/templates/layout.html.php new file mode 100644 index 0000000..743fe0d --- /dev/null +++ b/templates/layout.html.php @@ -0,0 +1,33 @@ + + + + + + <?=$title?> + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/templates/login.html.php b/templates/login.html.php new file mode 100644 index 0000000..ce449d9 --- /dev/null +++ b/templates/login.html.php @@ -0,0 +1,12 @@ + +
+ +
+ + + + + + + +
\ No newline at end of file diff --git a/templates/loginerror.html.php b/templates/loginerror.html.php new file mode 100644 index 0000000..131d964 --- /dev/null +++ b/templates/loginerror.html.php @@ -0,0 +1,3 @@ +

You are not logged in

+ +

You must be logged in to view this page. Click here to log in or Click here to register an account

\ No newline at end of file diff --git a/templates/loginsuccess.html.php b/templates/loginsuccess.html.php new file mode 100644 index 0000000..87a11b7 --- /dev/null +++ b/templates/loginsuccess.html.php @@ -0,0 +1,3 @@ +

Login Successful

+ +

You are now logged in.

\ No newline at end of file diff --git a/templates/logout.html.php b/templates/logout.html.php new file mode 100644 index 0000000..acdf7d3 --- /dev/null +++ b/templates/logout.html.php @@ -0,0 +1,3 @@ +

Logged out

+ +

You have been logged out

\ No newline at end of file diff --git a/templates/permissions.html.php b/templates/permissions.html.php new file mode 100644 index 0000000..96d91fa --- /dev/null +++ b/templates/permissions.html.php @@ -0,0 +1,13 @@ +

Edit name?>'s Permissions

+ +
+ + $value): ?> +
+ hasPermission($value)) echo 'checked'; ?> /> +
+ + + +
\ No newline at end of file diff --git a/templates/permissionserror.html.php b/templates/permissionserror.html.php new file mode 100644 index 0000000..6e00dbf --- /dev/null +++ b/templates/permissionserror.html.php @@ -0,0 +1,2 @@ +

Access Denied

+

You do not have permission to view this page.

\ No newline at end of file diff --git a/templates/register.html.php b/templates/register.html.php new file mode 100644 index 0000000..4b78037 --- /dev/null +++ b/templates/register.html.php @@ -0,0 +1,22 @@ + +
+

Your account could not be created, please check the following:

+ +
+ +
+ + + + + + + + + + +
\ No newline at end of file diff --git a/templates/registersuccess.html.php b/templates/registersuccess.html.php new file mode 100644 index 0000000..659fc33 --- /dev/null +++ b/templates/registersuccess.html.php @@ -0,0 +1,3 @@ +

Registration Successful

+ +

You are now registered on the Internet Joke Database

\ No newline at end of file