Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (99)
Showing
with 1353 additions and 21 deletions
MYSQL_ROOT_PASSWORD=96789678
MYSQL_HOST=db-wbd-1
MYSQL_DATABASE=audiolib
MYSQL_USER=roots
MYSQL_PASSWORD=96789678
MYSQL_PORT=3306
\ No newline at end of file
FROM php:8.0-apache
\ No newline at end of file
FROM php:8.0-apache
WORKDIR /var/www/html
COPY public/index.php .
RUN docker-php-ext-install mysqli pdo pdo_mysql
RUN a2enmod rewrite
EXPOSE 80
\ No newline at end of file
## Panduan Pengerjaan
Berikut adalah hal yang harus diperhatikan untuk pengumpulan tugas ini:
1. Buatlah grup pada Gitlab dengan format "IF3110-2023-01-XX", dengan XX adalah nomor kelompok (untuk K1 dan K2) atau kode kelompok (untuk K3).
2. Tambahkan anggota tim pada grup anda.
3. **Fork** pada repository ini dengan organisasi yang telah dibuat.
4. Ubah hak akses repository hasil Fork anda menjadi **private**.
5. Hal-hal yang harus diperhatikan.
* Silakan commit pada repository anda (hasil fork)
* Lakukan beberapa commit dengan pesan yang bermakna, contoh: “add register form”, “fix logout bug”, jangan seperti “final”, “benerin dikit”, “fix bug”.
* Disarankan untuk tidak melakukan commit dengan perubahan yang besar karena akan mempengaruhi penilaian (contoh: hanya melakukan satu commit kemudian dikumpulkan).
* Commit dari setiap anggota tim akan mempengaruhi penilaian.
* Jadi, setiap anggota tim harus melakukan commit yang berpengaruh terhadap proses pembuatan aplikasi.
* Sebagai panduan bisa mengikuti [semantic commit](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716).
6. Buatlah file README yang berisi:
* Deskripsi aplikasi web
* Daftar requirement
* Cara instalasi
* Cara menjalankan server
* Screenshot tampilan aplikasi (tidak perlu semua kasus, minimal 1 per halaman), dan
* Penjelasan mengenai pembagian tugas masing-masing anggota (lihat formatnya pada bagian pembagian tugas).
# Audiolibs
> Disusun untuk memenuhi Tugas Besar Milestone 1 - Monolitic PHP & Vanilla Web Application IF3110 Pengembangan Aplikasi Berbasis Web
## Daftar Isi
* [Deskripsi Aplikasi Web](#deskripsi-aplikasi-web)
* [Daftar Requirement](#daftar-requirementt)
* [Cara Instalasi](#cara-instalasi)
* [Cara Menjalankan Server](#cara-menjalankan-server)
* [Screenshot Tampilan Aplikasi](#screenshot-tampilan-aplikasi)
* [Pembagian Tugas](#deskripsi-aplikasi-web)
## Deskripsi Aplikasi Web
Aplikasi ini adalah aplikasi perpustakaan audiovisual. Di dalam aplikasi ini, pengguna dapat membaca buku yang telah disediakan oleh aplikasi. Selain membaca, pengguna juga dapat mendengarkan isi buku dengan narasi yang sudah disediakan oleh aplikasi pada setiap buku. Aplikasi ini dibuat dengan PHP murni beserta HTML, CSS, dan Javascript. DBMS yang digunakan adalah MySQL.
## Daftar Requirement
1. Login
2. Register
3. Daftar Buku (Booklist)
4. Detail Buku
5. Bookmark
6. Search, Sort, dan Filter
7. Tambah, Edit, dan Hapus Buku
8. Tambah, Edit, dan Hapus User
9. Tambah, Edit, dan Hapus Author
## Cara Instalasi
1. Unduh _repository_ ini dengan menggunakan perintah
`git clone https://gitlab.informatika.org/kenndave/tugas-besar-1.git`
2. Pastikan Anda telah melakukan instalasi Docker Desktop pada komputer Anda. Jika belum, Docker Desktop dapat diunduh pada link berikut:
`https://www.docker.com/products/docker-desktop/`
3. Lakukan pembuatan _image_ Docker yang akan digunakan oleh aplikasi dengan menjalankan perintah `docker build -t tubes-1:latest .` pada terminal _directory_ aplikasi
## Cara Menjalankan Server
1. Jalankan Docker Engine pada komputer Anda
2. Program dapat dijalankan dengan menjalankan perintah `docker compose up -d` pada terminal _directory_ aplikasi
3. Aplikasi web dapat diakses dengan menggunakan browser pada URL `http://localhost:8080/public/login`
4. Aplikasi web dapat dihentikan dengan menjalankan perintah `docker compose down` pada terminal _directory_ aplikasi
## Screenshot Tampilan Aplikasi
### Login
![Login Page](./screenshots/login-page.png)
### Register
![Register Page](./screenshots/register-page.png)
### Daftar Buku (Booklist)
![Booklist Page](./screenshots/booklist-page.png)
### Detail Buku
![Detail Book Page](./screenshots/detail-book.png)
### Bookmark
![Bookmark Page](./screenshots/bookmark-page.png)
### Search, Sort, dan Filter
![Search, Sort, and Filter](./screenshots/search-sort-filter.png)
### Tambah, Edit, dan Hapus Buku
![Book Page](./screenshots/book-admin-page.png)
![Add Book](./screenshots/add-book.png)
![Edit Book](./screenshots/edit-book.png)
### Tambah, Edit, dan Hapus User
![User Admin Page](./screenshots/user-admin-page.png)
![Add User](./screenshots/add-user-page.png)
![Edit User](./screenshots/edit-user.png)
![Delete User](./screenshots/delete-user.png)
### Tambah, Edit, dan Hapus Author
![Author Admin Page](./screenshots/author-page.png)
![Add Author](./screenshots/add-author.png)
![Edit Author](./screenshots/edit-author.png)
![Delete Author](./screenshots/delete-author.png)
## Pembagian Tugas
_Server Side_
| Fitur | NIM |
| ---------------------------------- | ----------------------------------------- |
| Login | 13521152, 13521145 |
| Register | 13521145 |
| Booklist | 13521152 |
| Detail Buku | 13521152 |
| Bookmark | 13521152 |
| Search, Sort, dan Filter | 13521145, 13521152 |
| Tambah, Edit, dan Hapus Buku | 13521145, 13521042 |
| Tambah, Edit, dan Hapus User | 13521145 |
| Tambah, Edit, dan Hapus Author | 13521152, 13521145 |
_Client Side_
| Fitur | NIM |
| ---------------------------------- | ----------------------------------------- |
| Login | 13521145 |
| Register | 13521042 |
| Booklist | 13521145, 13521152 |
| Detail Buku | 13521042 |
| Bookmark | 13521152 |
| Search, Sort, dan Filter | 13521145, 13521152 |
| Tambah, Edit, dan Hapus Buku | 13521145, 13521042 |
| Tambah, Edit, dan Hapus User | 13521145, 13521042 |
| Tambah, Edit, dan Hapus Author | 13521152 |
\ No newline at end of file
Options -Indexes
php_value upload_max_filesize 10M
php_value post_max_size 12M
\ No newline at end of file
<?php
// URL
define('BASEURL', 'http://localhost:8080/public');
define ('LOCALURL', '/var/www/html/public');
define('PAGEURL', '/var/www/html/app/views');
define('APPURL', '/var/www/html/app');
// Database
// define('HOST', 'localhost');
// define('DBNAME', 'audiolibs');
// define('USER', 'root');
// define('PASSWORD', '');
// define('PORT', '3306');
define('HOST', getenv('MYSQL_HOST'));
define('DBNAME', getenv('MYSQL_DATABASE'));
define('USER', getenv('MYSQL_USER') ?? 'root');
define('PASSWORD', getenv('MYSQL_PASSWORD'));
define('PORT', getenv('MYSQL_PORT'));
\ No newline at end of file
<?php
class Defaultx extends Controller {
public function index()
{
// Default method kalau gk ada metode yang dipanggil
$this->view('error/404');
}
}
\ No newline at end of file
<?php
session_start();
class Login extends Controller
{
public function index($page = 1)
{
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
$limit = 10;
$page = intval($page);
$offset = ($page - 1) * $limit;
$offset = intval($offset);
$data['book'] = $this->model('BookModel')->getAllBookList($limit, $offset);
$this->view('library/booklist', $data);
} else {
$this->view('login/login');
}
}
public function login()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Handle form submission
$username = $_POST['username'];
$password = $_POST['password'];
$this->model('UserModel')->getAllUser();
if ($this->authenticateUser($username, $password)) {
$_SESSION['user_role'] = 'user';
$_SESSION['username'] = $username;
$id = $this->model('UserModel')->getUserByUsername($username);
$_SESSION['id'] = $id['id'];
header('Location:' . BASEURL . '/user/index');
exit;
} else if ($this->authenticateAdmin($username, $password)) {
$_SESSION['user_role'] = 'admin';
$_SESSION['username'] = $username;
header('Location: ' . BASEURL . '/admin/index');
exit;
} else {
// Authentication failed, display an error message
$data['error'] = 'Invalid username or password';
$this->view('login/login', $data);
}
} else {
// Display the login form
$this->view('login/login');
}
}
public function logout()
{
session_destroy();
header('Location: ' . BASEURL . '/login/index');
exit;
}
// Add a method to authenticate the user against your database
private function authenticateUser($username, $password)
{
$user = $this->model('UserModel')->getUserByUsername($username);
if ($user && isset($user['password'])) {
$hashedPassword = password_hash($user['password'], PASSWORD_DEFAULT);
if (password_verify($password, $hashedPassword)) {
return true;
}
}
return false;
}
private function authenticateAdmin($username, $password)
{
$user = $this->model('UserModel')->getAdminByUsername($username);
if ($user && isset($user['password'])) {
$hashedPassword = password_hash($user['password'], PASSWORD_DEFAULT);
if (password_verify($password, $hashedPassword)) {
return true;
}
}
return false;
}
}
<?php
class Register extends Controller
{
public function index()
{
$this->view('register/register');
}
public function register()
{
try {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// isi form
$username = $_POST['newUsername'];
$password = $_POST['newPassword'];
$confirmPassword = $_POST['confirmPassword'];
// Cek dulu password & confirm passwordnya sama
if ($password !== $confirmPassword) {
throw new Exception("Password and confirm password do not match.");
}
// Fetch data from the database to check for existing usernames
$data['user'] = $this->model('UserModel')->getAllUser();
$array = array_column($data['user'], "username");
// Cek if the username already exists
if (!in_array($username, $array, true)) {
// User does not exist, insert into the database
$this->model('UserModel')->insertUser($username, $password);
// Successfully registered, redirect to the login page
header('Location:' . BASEURL . '/login/index');
exit;
} else {
throw new Exception("Username already exists.");
}
} else {
throw new Exception("Invalid request.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/error', ['error' => $error_message]);
}
}
}
<?php
session_start();
class User extends Controller
{
public function index($page = 1)
{
try {
// Check if the user is logged in as 'user'
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
$limit = 10;
$page = intval($page);
$offset = ($page - 1) * $limit;
$offset = intval($offset);
$data['book'] = $this->model('BookModel')->getAllBookList($limit, $offset);
$this->view('library/booklist', $data);
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function bookmark($page = 1)
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
$limit = 10;
$offset = ($page - 1) * $limit;
$data['book'] = $this->model('BookModel')->getAllBookmark($limit, $offset);
$this->view('bookmark/bookmark', $data);
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function addbookmark()
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
// Check if 'id' and 'bookid' were sent via POST
if (isset($_POST['id']) && isset($_POST['bookid'])) {
// Access the 'id' and 'bookid' values from $_POST
$id = $_POST['id'];
$bookid = $_POST['bookid'];
$this->model('BookModel')->addBookmark($id, $bookid);
$this->bookdetail($bookid);
} else {
throw new Exception("Invalid request.");
}
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function deletebookmark()
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
// Check if 'id' and 'bookid' were sent via POST
if (isset($_POST['id']) && isset($_POST['bookid'])) {
// Access the 'id' and 'bookid' values from $_POST
$id = $_POST['id'];
$bookid = $_POST['bookid'];
$this->model('BookModel')->deleteBookmark($id, $bookid);
$this->bookmark();
} else {
throw new Exception("Invalid request.");
}
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function bookdetail($page = 1)
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
$data['book'] = $this->model('BookModel')->getBookDetail($page);
$data['path'] = $this->model('BookModel')->getBookFilename($page);
$this->view('library/detailbook', $data);
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function bookmarkSearch($page = 1)
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$searchInput = isset($_POST['search']) ? $_POST['search'] : '';
$sortSelect = isset($_POST['sortSelect']) ? $_POST['sortSelect'] : 'title';
$sortOrder = isset($_POST['sortOrder']) ? $_POST['sortOrder'] : 'ASC';
$filterSelect = isset($_POST['filterSelect']) ? $_POST['filterSelect'] : 'none';
$filterQuery = isset($_POST['filterQuery']) ? $_POST['filterQuery'] : '';
$limit = 10;
$page = intval($page);
$offset = ($page - 1) * $limit;
$offset = intval($offset);
// Perform a search using the parameters and the model method
$data['book'] = $this->model('BookModel')->searchBookmark($searchInput, $sortSelect, $sortOrder, $filterSelect, $filterQuery, $limit, $offset);
if (empty($data['book'])) {
$data['message'] = 'No results found.';
}
$this->view('bookmark/bookmark', $data);
} else {
throw new Exception("Invalid request.");
}
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function booklistSearch($page = 1)
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'user') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$searchInput = isset($_POST['search']) ? $_POST['search'] : '';
$sortSelect = isset($_POST['sortSelect']) ? $_POST['sortSelect'] : 'title';
$sortOrder = isset($_POST['sortOrder']) ? $_POST['sortOrder'] : 'ASC';
$filterSelect = isset($_POST['filterSelect']) ? $_POST['filterSelect'] : 'none';
$filterQuery = isset($_POST['filterQuery']) ? $_POST['filterQuery'] : '';
$limit = 10;
$page = intval($page);
$offset = ($page - 1) * $limit;
$offset = intval($offset);
// Perform a search using the parameters and the model method
$data['book'] = $this->model('BookModel')->searchBookList($searchInput, $sortSelect, $sortOrder, $filterSelect, $filterQuery, $limit, $offset);
$this->view('library/booklist', $data);
} else {
$limit = 10;
$page = intval($page);
$offset = ($page - 1) * $limit;
$offset = intval($offset);
$data['book'] = $this->model('BookModel')->getAllBookList($limit, $offset);
if (empty($data['book'])) {
$data['message'] = 'No results found.';
}
$this->view('library/booklist', $data);
}
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
}
\ No newline at end of file
<?php
session_start();
class Admin extends Controller {
public function index(){
try {
if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== 'admin') {
throw new Exception("Unauthorized access.");
}
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$this->view('admin/sidebar', $data);
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function bookadmin(){
try {
if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== 'admin') {
throw new Exception("Unauthorized access.");
}
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$this->view('admin/bookadmin', $data);
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function useradmin(){
try {
if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== 'admin') {
throw new Exception("Unauthorized access.");
}
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', $data);
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function authoradmin(){
try {
if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== 'admin') {
throw new Exception("Unauthorized access.");
}
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', $data);
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function model($model){
require_once '../app/models/' . $model . '.php';
return new $model;
}
public function addBook()
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Buat path image audio
$imageDir = LOCALURL . "/img/";
$audioDir = LOCALURL . "/audio/";
// Ambil nilai
$newTitle = $_POST["addTitle"];
$selectedAuthor = $_POST["pickedAuthor"];
$selectedCategory = $_POST["pickedCategory"];
$newContent = $_POST["addContent"];
$fileAudio = $_FILES['addAudio']['name'];
$fileTmpAudio = $_FILES['addAudio']['tmp_name'];
$fileImage = $_FILES['addImage']['name'];
$fileTmpImage = $_FILES['addImage']['tmp_name'];
$audioFilePath = $audioDir . $fileAudio;
$imageFilePath = $imageDir . $fileImage;
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$array = array_column($data['book'], "title");
// Cek exist ato g usernya, cek string kosong ato ngga
if (!in_array($newTitle, $array, true) && !(empty($newTitle) || empty($newContent) || ( empty ($newTitle) && empty($newContent) ))){
$this->model('BookModel')->insertBook($newTitle, $newContent, $selectedAuthor, $selectedCategory, $fileAudio, $fileImage);
move_uploaded_file($fileTmpAudio, $audioFilePath);
move_uploaded_file($fileTmpImage, $imageFilePath);
} else {
throw new Exception("Invalid input data.");
}
}
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$this->view('admin/bookadmin', $data);
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function addUser(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin' ){
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$newUsername = $_POST['newUsername'];
$newPassword = $_POST['newPassword'];
$data['user'] = $this->model('UserModel')->getAllUser();
$array = array_column($data['user'], "username");
// Cek stringnya kosong ato g && exist ato g usernya
if (empty($newUsername) || empty($newPassword)) {
throw new Exception("Username and Password cannot be empty.");
}
if (in_array($newUsername, $array, true)) {
throw new Exception("Username already exists.");
}
$this->model('UserModel')->insertUser($newUsername, $newPassword);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', ['error' => $error_message] + $data);
return;
}
}
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', $data);
} else {
$this->view('error/404');
}
}
public function editBook()
{
try {
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Buat path image audio
$imageDir = LOCALURL . "/img/";
$audioDir = LOCALURL . "/audio/";
// Ambil nilai
$newTitle = $_POST["newTitle"];
$oldTitle = $_POST["oldTitle"];
$selectedAuthor = $_POST["selectedAuthor"];
$selectedCategory = $_POST["selectedCategory"];
$newContent = $_POST["newContent"];
$bookid = $_POST["bookid"];
$fileAudio = $_FILES['audio']['name'];
$fileTmpAudio = $_FILES['audio']['tmp_name'];
$fileImage = $_FILES['image']['name'];
$fileTmpImage = $_FILES['image']['tmp_name'];
$audioFilePath = $audioDir . $fileAudio;
$imageFilePath = $imageDir . $fileImage;
$data['book'] = $this->model('BookModel')->getAllBook();
$array = array_column($data['book'], "title");
// Cek title kosong atau udah exist di db atau gk diganti
if(!empty($newTitle) && (!in_array($newTitle, $array, true) || $newTitle === $oldTitle) && (isset($fileAudio) && isset($fileImage))){
$this->model('BookModel')->updateBook($bookid, $newTitle, $selectedAuthor, $newContent, $selectedCategory, $fileAudio, $fileImage);
move_uploaded_file($fileTmpAudio, $audioFilePath);
move_uploaded_file($fileTmpImage, $imageFilePath);
} else {
throw new Exception("Invalid input data.");
}
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$this->view('admin/bookadmin', $data);
}
} else {
throw new Exception("Unauthorized access.");
}
} catch (Exception $e) {
$error_message = $e->getMessage();
$this->view('error/403', ['error' => $error_message]);
}
}
public function editUser(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
// Dapetin nilai dari input formnye ya
$oldUsername = $_POST['username'];
$newUsername = $_POST['newUsername'];
$newPassword = $_POST['newPassword'];
$userId = $_POST['userId'];
$data['user'] = $this->model('UserModel')->getAllUser();
// Bikin kolom array list username buat pengecekkan
$array = array_column($data['user'], "username");
// Cek password kosong dan user kosong atau udah exist di db atau gk diganti
if (empty($newUsername) || empty($newPassword)) {
throw new Exception("Username and Password cannot be empty.");
}
if (in_array($newUsername, $array, true) && $newUsername !== $oldUsername) {
throw new Exception("Username already exists.");
}
$this->model('UserModel')->updateUser($userId, $newUsername, $newPassword);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', ['error' => $error_message] + $data);
return;
}
}
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', $data);
}
else {
$this->view('login/login');
}
}
public function addAuthor(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin' ){
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$newAuthorName = $_POST['newAuthorName'];
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$authorNames = array_column($data['authors'], "author_name");
// Cek exist atau kosong
if (empty($newAuthorName)) {
throw new Exception("Author name cannot be empty.");
}
if (in_array($newAuthorName, $authorNames, true)) {
throw new Exception("Author name already exists.");
}
$this->model('AuthorModel')->insertAuthor($newAuthorName);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', ['error' => $error_message] + $data);
return;
}
}
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', $data);
} else {
$this->view('login/login');
}
}
public function editAuthor(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$newAuthorName = $_POST['newAuthorName'];
$oldAuthorName = $_POST['authorName'];
$authorid = $_POST['authorId'];
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$authorNames = array_column($data['authors'], "author_name");
// Cek exist atau kosong
if (empty($newAuthorName)) {
throw new Exception("Author name cannot be empty.");
}
if (in_array($newAuthorName, $authorNames, true) && $newAuthorName !== $oldAuthorName) {
throw new Exception("Author name already exists.");
}
$this->model('AuthorModel')->updateAuthor($authorid, $newAuthorName);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', ['error' => $error_message] + $data);
return;
}
}
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', $data);
} else {
$this->view('login/login');
}
}
public function deleteAuthor(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$authorId = $_POST['deleteId'];
$this->model('AuthorModel')->deleteAuthor($authorId);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', ['error' => $error_message] + $data);
return;
}
}
$data['authors'] = $this->model('AuthorModel')->getAllAuthor();
$this->view('admin/authoradmin', $data);
} else {
$this->view('login/login');
}
}
public function deleteUser(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$userId = $_POST['deleteId'];
$this->model('UserModel')->deleteUser($userId);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', ['error' => $error_message] + $data);
return;
}
}
$data['user'] = $this->model('UserModel')->getAllUser();
$this->view('admin/useradmin', $data);
} else {
$this->view('login/login');
}
}
public function deleteBook(){
if (isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$bookId = $_POST['deleteId'];
$this->model('BookModel')->deleteBook($bookId);
} catch (Exception $e) {
// Handle the error, you can redirect or display a message
$error_message = $e->getMessage();
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$this->view('admin/bookadmin', ['error' => $error_message] + $data);
return;
}
}
$data['book'] = $this->model('BookModel')->getAllBookAdmin();
$data['author'] = $this->model('AuthorModel')->getAuthor();
$this->view('admin/bookadmin', $data);
} else {
$this->view('login/login');
}
}
}
\ No newline at end of file
<?php
class App {
protected $controller;
protected $method;
protected $params = [];
public function __construct(){
// require_once ('../app/controllers/Defaultx.php');
$this->controller = 'Defaultx';
$this->method = 'index';
$url = $this->parseURL();
// Index pertama adalah controller, kedua adalah metode. Intinya ini cari
// Ada controller sesuai url user gak? kalau ada bakal ditimpa. Kalau gak,
// Masih default (dinamain defaultx karena default doang gak bisa).
$isControllerNull = $url[0] ?? null;
if( isset($isControllerNull) && file_exists('../app/controllers/' . $url[0] . '.php' ) )
{
$this->controller = $url[0];
// Unset itu buat ngilangin controllernya dari array
// jadi url[0] deleted, tapi gk geser jadi tetep ada
// di index ke-1, dst kalau ada.
unset($url[0]);
}
// Dari IF ini, kalau ada controller udah ditentuin
require_once '../app/controllers/' . $this->controller . '.php';
$this->controller = new $this->controller;
// Baik default atau non default, controller telah di set.
// Sekarang cari metode dalem controller
if( isset($url[1]) ){
if(method_exists($this->controller, $url[1]) ){
// kalau ada, ditimpa yang tadinya by default, index
$this->method = $url[1];
// buang lagi di index 1, metode diambil.
unset($url[1]);
}
}
// ini lanjut cari parameters
if (!empty($url)){
// Ngambil values dalam array, yaitu parameters
$this->params = array_values($url);
}
// Jalanin controller & method, +kirim params kalo ada
call_user_func_array([$this->controller, $this->method], $this->params);
}
public function parseURL(){
if ( isset($_GET['url']) ){
$url = rtrim($_GET['url'], '/'); // Ngapus / terakhir
$url = filter_var($url, FILTER_SANITIZE_URL); // Filtering URLnya dari karakter2 aneh
$url = explode('/', $url);
return $url;
}
}
}
\ No newline at end of file
<?php
class Controller
{
// Pertama controller ngambil view yang disearch
// viewnya itu file apa.
// dan data itu bisa berupa parameter.
public function view($view, $data = []){
require_once '../app/views/' . $view . '.php';
}
public function model($model)
{
require_once __DIR__ . '/../models/' . $model . '.php';
return new $model();
}
}
\ No newline at end of file
<?php
require_once('tables.php');
class Database
{
public $host = HOST;
public $db_name = DBNAME;
public $user = USER;
public $password = PASSWORD;
public $port = PORT;
public $dbs;
public $statement;
public function __construct()
{
$dsn = 'mysql:host=' . $this->host . ';port=' . $this->port . ';dbname=' . $this->db_name;
$option = [
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
];
try {
$this->dbs = new PDO($dsn, $this->user, $this->password, $option);
// $this->dbs->exec("USE audiolibs");
} catch (PDOException $e) {
die($e->getMessage());
}
try {
$this->dbs->exec(Tables::AUTHOR_TABLE);
$this->dbs->exec(Tables::USER_TABLE);
$this->dbs->exec(Tables::BOOK_TABLE);
$this->dbs->exec(Tables::INVENTORY_TABLE);
} catch (PDOException $e) {
die($e->getMessage());
}
}
public function query($query){
$this->statement = $this->dbs->prepare($query);
}
public function bind($param, $value, $type = null)
{
if( is_null($type) ) {
switch( true ) {
case is_int($value) :
$type = PDO::PARAM_INT;
break;
case is_bool($value) :
$type = PDO::PARAM_BOOL;
break;
case is_null($value) :
$type = PDO::PARAM_NULL;
break;
default:
$type = PDO::PARAM_STR;
}
}
$this->statement->bindValue($param, $value, $type);
}
public function execute()
{
$this->statement->execute();
}
public function resultSet(){
$this->execute();
return $this->statement->fetchAll(PDO::FETCH_ASSOC);
}
public function single(){
$this->execute();
return $this->statement->fetch(PDO::FETCH_ASSOC);
}
public function rowCount()
{
try {
return $this->statement->rowCount();
} catch (PDOException $e) {
die($e->getMessage());
}
}
}
\ No newline at end of file
<?php
class Tables
{
public const AUTHOR_TABLE =
"CREATE TABLE IF NOT EXISTS author (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL
);";
public const USER_TABLE =
"CREATE TABLE IF NOT EXISTS user(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
admin BOOLEAN NOT NULL
);";
public const BOOK_TABLE =
"CREATE TABLE IF NOT EXISTS book (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(256) UNIQUE NOT NULL,
content TEXT NOT NULL,
author_id INT NOT NULL,
audio_path VARCHAR(256) NOT NULL,
image_path VARCHAR(256) NOT NULL,
category VARCHAR(256) NOT NULL,
FOREIGN KEY(author_id) REFERENCES author(id) ON DELETE CASCADE
);";
public const INVENTORY_TABLE =
"CREATE TABLE IF NOT EXISTS inventory (
user_id INT NOT NULL,
book_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
FOREIGN KEY (book_id) REFERENCES book(id) ON DELETE CASCADE
);";
}
\ No newline at end of file
<?php
require_once 'core/App.php';
require_once 'core/Controller.php';
require_once 'core/Database.php';
require_once 'config/config.php';
<?php
interface ControllerInterface
{
public function index();
}
\ No newline at end of file
<?php
interface ViewInterface
{
public function render();
}
\ No newline at end of file
<?php
class AuthorModel
{
private $table = 'author';
private $database;
public function __construct()
{
$this->database = new Database;
}
public function getAllAuthor(){
$this->database->query('SELECT * FROM author');
return $this->database->resultSet();
}
public function getAuthor(){
$this->database->query('SELECT name FROM author');
return $this->database->resultSet();
}
public function insertAuthor($newAuthorName){
$this->database->query('INSERT IGNORE INTO author (id, name) VALUES (NULL, :newAuthorName)');
$this->database->bind('newAuthorName', $newAuthorName);
$this->database->execute();
}
public function updateAuthor($authorid, $newUsername){
$this->database->query('UPDATE ' . $this->table . ' SET name = :newName WHERE author.id = :authorid');
$this->database->bind('newName', $newUsername);
$this->database->bind('authorid', $authorid);
$this->database->execute();
}
public function deleteAuthor($authorId){
$this->database->query('DELETE FROM ' . $this->table . ' WHERE id = :id');
$this->database->bind('id', $authorId);
$this->database->execute();
}
}
\ No newline at end of file
<?php
class BookModel
{
private $table = 'book';
private $database;
public function __construct()
{
$this->database = new Database;
}
public function getAllBook(){
$this->database->query('SELECT * FROM book');
return $this->database->resultSet();
}
public function getAllBookAdmin(){
$this->database->query('SELECT book.id, title, content, author.name, audio_path, image_path, category FROM book JOIN author on book.author_id = author.id');
return $this->database->resultSet();
}
public function tambahDataAuthor(){
$query = "INSERT INTO author
VALUES
('', Jack)";
$this->database->query($query);
$this->database->execute();
}
public function tambahDataBuku(){
$query = "INSERT INTO buku
VALUES
('', Title1, 1, url_audio, url_image, cat1)";
$this->database->query($query);
$this->database->execute();
}
public function getCategory(){
$this->database->query('SELECT DISTINCT category FROM book');
return $this->database->resultSet();
}
public function insertBook($newTitle, $newContent, $pickedAuthor, $pickedCategory, $newAudio, $newImage){
$this->database->query('INSERT IGNORE INTO book (id, title, content, author_id, audio_path, image_path, category) VALUES (NULL, :newTitle, :newContent, (SELECT id FROM author WHERE author.name = :pickedAuthor), :newAudio, :newImage, :pickedCategory)');
// $newAudio = "audioex.mp3";
// $newImage = "imageex.png";
$this->database->bind('newTitle', $newTitle);
$this->database->bind('newContent', $newContent);
$this->database->bind('newAudio', $newAudio);
$this->database->bind('newImage', $newImage);
$this->database->bind('pickedAuthor', $pickedAuthor);
$this->database->bind('pickedCategory', $pickedCategory);
$this->database->execute();
}
public function updateBook($bookid, $newTitle, $selectedAuthor, $newContent, $selectedCategory, $newAudio, $newImage){
$this->database->query('UPDATE book SET title = :newTitle, content = :newContent, audio_path = :newAudio, image_path = :newImage, author_id = (SELECT id FROM author WHERE author.name = :selectedAuthor), category = :newCategory WHERE book.id = :bookid');
$this->database->bind('bookid', $bookid);
$this->database->bind('newTitle', $newTitle);
$this->database->bind('newContent', $newContent);
$this->database->bind('newAudio', $newAudio);
$this->database->bind('newImage', $newImage);
$this->database->bind('selectedAuthor', $selectedAuthor);
$this->database->bind('newCategory', $selectedCategory);
$this->database->execute();
}
public function deleteBook($id){
$query = "DELETE FROM book WHERE id = :id";
$this->database->query($query);
$this->database->bind('id',$id);
$this->database->execute();
return 1;
}
public function getAllBookmark($limit, $offset){
$this->database->query("SELECT book.id, title, author.name, category, audio_path, image_path FROM book JOIN author ON book.author_id = author.id JOIN inventory ON book.id = inventory.book_id JOIN user ON user.id = inventory.user_id WHERE user.id = :id LIMIT $limit OFFSET $offset");
$this->database->bind('id', $_SESSION['id']);
return $this->database->resultSet();
}
public function getAllBookList($limit, $offset){
$this->database->query("SELECT book.id, title, author.name, category, audio_path, image_path FROM book JOIN author ON book.author_id = author.id LIMIT $limit OFFSET $offset");
return $this->database->resultSet();
}
public function getBookDetail($id){
$this->database->query("SELECT book.id, title, author.name, category FROM book JOIN author ON book.author_id = author.id WHERE book.id = :id");
$this->database->bind('id', $id);
return $this->database->single();
}
public function addBookmark($id, $bookid){
// Check if the tuple exists
$this->database->query("SELECT * FROM inventory WHERE user_id = :id AND book_id = :bookid");
$this->database->bind('id', $id);
$this->database->bind('bookid', $bookid);
$this->database->execute();
$existingTuple = $this->database->single();
if (!$existingTuple) {
// The tuple doesn't exist, so insert it
$this->database->query("INSERT INTO inventory (user_id, book_id) VALUES (:id, :bookid)");
$this->database->bind('id', $id);
$this->database->bind('bookid', $bookid);
$this->database->execute();
}
}
public function deleteBookmark($id, $bookid){
$this->database->query("DELETE FROM inventory WHERE user_id = :id AND book_id = :bookid");
$this->database->bind('id', $id);
$this->database->bind('bookid', $bookid);
$this->database->execute();
}
public function getBookFilename($id){
$this->database->query("SELECT audio_path, image_path FROM book WHERE id = :id");
$this->database->bind('id', $id);
return $this->database->single();
}
public function getAllBookFilename(){
$this->database->query("SELECT audio_path, image_path FROM book");
return $this->database->resultSet();
}
public function searchBookmark($searchInput, $sortSelect, $sortOrder, $filterSelect, $filterQuery, $limit, $offset){
// Construct the SQL query based on the provided parameters
$sql = "SELECT book.id, title, author.name, category, audio_path, image_path FROM book JOIN author ON book.author_id = author.id JOIN inventory ON book.id = inventory.book_id JOIN user ON user.id = inventory.user_id WHERE 1=1"; // Initial WHERE condition
if ($filterSelect && $filterQuery) {
$sql .= " AND $filterSelect = '$filterQuery'";
}
if ($searchInput) {
// Sanitize the search input to prevent SQL injection
// $searchInput = mysqli_real_escape_string($this->database->getConnection(), $searchInput);
// Create a search query using LIKE clause for substring search
$sql .= " AND (title LIKE '%$searchInput%' OR author.name LIKE '%$searchInput%')";
}
if ($sortSelect != "none") {
// Check for valid sort order (ASC or DESC)
if ($sortOrder === 'ascending') {
$sortOrder = 'ASC';
} elseif ($sortOrder === 'descending') {
$sortOrder = 'DESC';
} else {
// Default to ascending if sortOrder is not valid
$sortOrder = 'ASC';
}
if ($sortSelect = "author"){
$sortSelect = "author.name";
}
$sql .= " ORDER BY $sortSelect $sortOrder";
}
$sql .= " LIMIT $limit OFFSET $offset";
// Execute the query and return the results
$this->database->query($sql);
return $this->database->resultSet();
}
public function searchBookList($searchInput, $sortSelect, $sortOrder, $filterSelect, $filterQuery, $limit, $offset){
// Construct the SQL query based on the provided parameters
$sql = "SELECT book.id, title, author.name, category, audio_path, image_path FROM book JOIN author ON book.author_id = author.id WHERE 1=1"; // Initial WHERE condition
if ($filterSelect && $filterQuery) {
$sql .= " AND $filterSelect = '$filterQuery'";
}
if ($searchInput) {
// Sanitize the search input to prevent SQL injection
// $searchInput = mysqli_real_escape_string($this->database->getConnection(), $searchInput);
// Create a search query using LIKE clause for substring search
$sql .= " AND (title LIKE '%$searchInput%' OR author.name LIKE '%$searchInput%')";
}
if ($sortSelect != "none") {
// Check for valid sort order (ASC or DESC)
if ($sortOrder === 'ascending') {
$sortOrder = 'ASC';
} elseif ($sortOrder === 'descending') {
$sortOrder = 'DESC';
} else {
// Default to ascending if sortOrder is not valid
$sortOrder = 'ASC';
}
if ($sortSelect = "author"){
$sortSelect = "author.name";
}
$sql .= " ORDER BY $sortSelect $sortOrder";
}
$sql .= " LIMIT $limit OFFSET $offset";
// Execute the query and return the results
$this->database->query($sql);
return $this->database->resultSet();
}
public function pageCount()
{
$this->database->query('SELECT COUNT(*) FROM book JOIN inventory ON book.id = inventory.book_id JOIN user ON user.id = inventory.user_id');
$count = $this->database->single(); // Assuming you have a method like singleColumn()
// Convert the count value to an integer
$count = intval($count);
return $count;
}
}
\ No newline at end of file
<?php
class UserModel
{
private $table = 'user';
private $database;
public function __construct()
{
$this->database = new Database;
}
public function getAllUser(){
$this->database->query('SELECT * FROM user WHERE admin = 0');
return $this->database->resultSet();
}
public function getAllUsername(){
$this->database->query('SELECT username FROM user WHERE admin = 0');
return $this->database->resultSet();
}
public function getUserByUsername($username){
$this->database->query('SELECT * FROM ' . $this->table . ' WHERE username = :username' . ' AND admin = 0');
$this->database->bind('username', $username);
return $this->database->single();
}
public function getAdminByUsername($username){
$this->database->query('SELECT * FROM ' . $this->table . ' WHERE username = :username' . ' AND admin = 1');
$this->database->bind('username', $username);
return $this->database->single();
}
public function updateUser($userId, $newUsername, $newPassword){
$this->database->query('UPDATE ' . $this->table . ' SET username = :newUsername, password = :newPassword WHERE id = :userId');
$this->database->bind('newUsername', $newUsername);
$this->database->bind('newPassword', $newPassword); // Hash the new password
$this->database->bind('userId', $userId);
$this->database->execute();
}
public function insertUser($newUsername, $newPassword){
$this->database->query('INSERT IGNORE INTO user (id, username, password, admin) VALUES (NULL, :newUsername, :newPassword, 0)');
$this->database->bind('newUsername', $newUsername);
$this->database->bind('newPassword', $newPassword);
$this->database->execute();
}
public function deleteUser($id){
$this->database->query('DELETE FROM user WHERE id = :id');
$this->database->bind('id', $id);
$this->database->execute();
}
}
\ No newline at end of file