diff --git a/.env b/.env new file mode 100644 index 0000000000000000000000000000000000000000..d323e444723da567972530ed327f153dbde8b911 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +POSTGRES_PASSWORD=admintubes +POSTGRES_USER=utubes1 +POSTGRES_DB=magictune +POSTGRES_HOST=db-tubes-1 +POSTGRES_PORT=5432 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..06c0328387eabc21adbbd11103efc8df8f55108d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM php:8.0-apache + +# Menetapkan direktori kerja ke /var/www/html +WORKDIR /var/www/html + +# Menyalin berkas index.php dari direktori src/public ke direktori kerja +COPY src/public/index.php . + +# Menginstal ekstensi PHP dan paket digunakan +RUN apt-get -y update \ + && apt-get -y upgrade \ + && apt-get install -y ffmpeg \ + && apt-get install -y libpq-dev + +# Menginstal ekstensi PHP PDO dan PDO PostgreSQL +RUN docker-php-ext-install pdo pdo_pgsql + +# Mengaktifkan mod_rewrite di Apache +RUN a2enmod rewrite + +# Mengekspos port 80 agar dapat diakses dari luar container +EXPOSE 80 diff --git a/README.md b/README.md index ea198365e8ea223980619cb461f0e3450091ff5d..82450ee3a51c11c5596312da3fbb524f6332f779 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,153 @@ -# IF3110-2023-02-43-PHP APP - - - -## Getting started - -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - +<!-- ## 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). --> +# Tugas + +## Instalasi + +Lakukan clone pada repository ini + +```sh +git clone git@gitlab.informatika.org:akmaldika/if-3110-2023-01-43.git ``` -cd existing_repo -git remote add origin https://gitlab.informatika.org/if3110-2023-02-43/if3110-2023-02-43-php-app.git -git branch -M main -git push -uf origin main -``` - -## Integrate with your tools - -- [ ] [Set up project integrations](https://gitlab.informatika.org/if3110-2023-02-43/if3110-2023-02-43-php-app/-/settings/integrations) - -## Collaborate with your team - -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) +## Cara Menjalankan +1. Pindah ke directory repository -*** - -# Editing this README - -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. - -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. - -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. - -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. - -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. +```sh +cd if-3110-2023-01-43 +``` -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. +2. Build aplikasi melalui docker -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. +```sh +docker-compose build -t tubes-1:latest . +``` -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. +3. Jalankan aplikasi melalui docker -## License -For open source projects, say how it is licensed. +```sh +docker-compose up +``` -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +4. Setelah itu aplikasi akan berjalan di localhost anda pada port 8008. Buka browser dan masukkan `localhost:8080\public\` pada url. + +## Pembagian Tugas + +### _UI/UX Design_ + +| Design | NIM | +| --------------- | ------------------ | +| Login | 13521053 | +| Register | 13521053 | +| User | 13521070 | +| Home | 13521104 | +| Daftar Lagu | 13521104 | +| Tambah Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Daftar Album | 13521104 | +| Tambah Album | 13521104 | +| Edit Album | 13521104 | +| Music Player | 13521104 | +| Search | 13521104 | +| Sort dan Filter | 13521104 | +| Card List | 13521104 | +| Album List | 13521104 | +| Navigation Bar | 13521104 | +| Pagination | 13521070, 13521104 | + +### _Server Side_ + +| Fitur | NIM | +| --------------- | -------- | +| Login | 13521053 | +| Register | 13521053 | +| User | 13521070 | +| Home | 13521104 | +| Daftar Album | 13521104 | +| Search | 13521104 | +| Daftar Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Daftar Album | 13521104 | +| Edit Album | 13521104 | +| Tambah Lagu | 13521104 | +| Tambah Album | 13521104 | +<!-- | Sort dan Filter | | --> +<!-- | Pagination | | --> + +### _Client Side_ + +| Fitur | NIM | +| --------------- | -------- | +| Login | 13521053 | +| Register | 13521053 | +| User | 13521070 | +| Home | 13521104 | +| Music Player | 13521104 | +| Daftar Album | 13521104 | +| Search | 13521104 | +| Daftar Lagu | 13521104 | +| Tambah Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Hapus Lagu | 13521104 | +| Tambah Album | 13521104 | +| Daftar Album | 13521104 | +| Edit Album | 13521104 | +| Hapus Album | 13521104 | +<!-- | Sort dan Filter | | --> + +| Page | NIM | +| ------------ | -------- | +| Login | 13521053 | +| Register | 13521053 | +| User | 13521070 | +| Home | 13521104 | +| Daftar Lagu | 13521104 | +| Tambah Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Daftar Album | 13521104 | +| Tambah Album | 13521104 | +| Edit Album | 13521104 | + +| Component | NIM | +| --------------- | -------- | +| Music Player | 13521104 | +| Search | 13521104 | +| Sort dan Filter | 13521104 | +| Card List | 13521104 | +| Album List | 13521104 | +| Navigation Bar | 13521104 | +| Pagination | 13521104 | + +### _Database_ + +| Fitur | NIM | +| ----- | ------------------ | +| User | 13521070 | +| Song | 13521070, 13521104 | +| Album | 13521070, 13521104 | + +### _Setup_ + +| Fitur | NIM | +| -------- | -------- | +| Database | 13521070 | +| Docker | 13521070 | +| MVC | 13521104 | diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..8fe8b35b20dad3ef1cbc236f49ea970a6d5ce882 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3.3' + +services: + # Service untuk web server dan PHP + web: + container_name: magic-tune + hostname: web-tubes-1 + image: tubes-1:latest + ports: + - 8080:80 + volumes: + - ./src:/var/www/html + - ./README.md:/var/www/html/README.md + depends_on: + - db + + # Service untuk PostgreSQL + db: + container_name: db-magic-tune + hostname: db-tubes-1 + image: postgres:latest + restart: always + ports: + - "5433:5432" # Port host:port kontainer PostgreSQL + env_file: + - .env + volumes: + - postgres-data:/var/lib/postgresql/data # Menyimpan data PostgreSQL di volume bernama pg_data + - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d # Mount direktori script SQL + +volumes: + postgres-data: # Definisi volume untuk data PostgreSQL + diff --git a/docker-entrypoint-initdb.d/init.sql b/docker-entrypoint-initdb.d/init.sql new file mode 100644 index 0000000000000000000000000000000000000000..bfd556eb92558e8d64bdb7b86984380f720e7e90 --- /dev/null +++ b/docker-entrypoint-initdb.d/init.sql @@ -0,0 +1,52 @@ +-- CREATE TABLE untuk tabel "user" +CREATE TABLE IF NOT EXISTS "user" ( + user_id SERIAL PRIMARY KEY, + email VARCHAR(256) UNIQUE NOT NULL, + username VARCHAR(256) UNIQUE NOT NULL, + fullname VARCHAR(256) NOT NULL, + password VARCHAR(256) NOT NULL, + photo_profile VARCHAR(256) DEFAULT 'default_photo_profile.png', + is_admin BOOLEAN NOT NULL DEFAULT false +); + +-- CREATE TABLE untuk tabel "album" +CREATE TABLE IF NOT EXISTS album ( + album_id SERIAL PRIMARY KEY, + judul VARCHAR(64) NOT NULL, + penyanyi VARCHAR(128) NOT NULL, + image VARCHAR(256) NOT NULL, + year INT NOT NULL +); + +-- CREATE TABLE untuk tabel "song" +CREATE TABLE IF NOT EXISTS song ( + song_id SERIAL PRIMARY KEY, + judul VARCHAR(64) NOT NULL, + penyanyi VARCHAR(128), + year INT NOT NULL, + audio VARCHAR(256) NOT NULL, + image VARCHAR(256), + album_id INT NOT NULL, + FOREIGN KEY (album_id) REFERENCES album (album_id) ON UPDATE CASCADE ON DELETE CASCADE +); + +-- INSERT data awal ke tabel "user" +INSERT INTO "user" (user_id, email, username, fullname, password, is_admin) +VALUES + (1, 'admin@example.com', 'admin1', 'Administrator', 'adminpass1', true), + (2, 'user1@example.com', 'user1', 'Pengguna 1', 'upassword1', false), + (3, 'user2@example.com', 'user2', 'Pengguna 2', 'upasswaord2', false); + +-- INSERT data awal ke tabel "album" +INSERT INTO album (album_id, judul, penyanyi, image, year) +VALUES + (1, 'Album 1', 'Penyanyi 1', 'image16.jpg', 2023), + (2, 'Album 2', 'Penyanyi 2', 'image15.jpg', 2022), + (3, 'Album 3', 'Penyanyi 3', 'image16.jpg', 2024); + +-- INSERT data awal ke tabel "song" +INSERT INTO song (song_id, judul, penyanyi, year, audio, image, album_id) +VALUES + (1, 'Lagu 1', 'Penyanyi A', 2023, 'Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3', 'image14.png', 1), + (2, 'Lagu 2', 'Penyanyi B', 2022, 'Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3', 'image15.png', 2), + (3, 'Lagu 3', 'Penyanyi C', 2024, 'Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3', 'image14.png', 1); \ No newline at end of file diff --git a/scripts/build-image.sh b/scripts/build-image.sh new file mode 100644 index 0000000000000000000000000000000000000000..b773a0a7e0706ef42a063282933335a18c636b5d --- /dev/null +++ b/scripts/build-image.sh @@ -0,0 +1,8 @@ +docker build -t tubes-1:latest . + + +# # Eksekusi pg_dump dalam kontainer +# docker exec db-magic-tune pg_dump -U utubes1 -d magictune -f /docker-entrypoint-initdb.d/init.sql + +# # Menyalin file backup dari kontainer ke sistem lokal +# docker cp db-magic-tune:/docker-entrypoint-initdb.d/init.sql ~/backup.sql \ No newline at end of file diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3c02b42ffc1300c16d413e9d43eb294b2a251c6f --- /dev/null +++ b/src/README.md @@ -0,0 +1,149 @@ +<!-- # Daftar isi --> +## 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). + + + +## Instalasi +1. Lakukan clone pada repository ini +```sh +git clone https://gitlab.informatika.org/if3110-2022-k02-01-30/if-3110-2022-k-02-01-30.git +``` + +2. Pindah ke directory repository +```sh +cd if-3110-2022-k-02-01-30 +``` + +3. Build aplikasi melalui docker +```sh +docker-compose build +``` + +4. Jalankan aplikasi melalui docker +```sh +docker-compose up +``` + +1. Setelah itu aplikasi akan berjalan di localhost anda pada port 8008. Buka browser dan masukkan `localhost:8080` pada url. + + +## Pembagian Tugas + +### _UI/UX Design_ + +| Design | NIM | +| ------------------------ | -------- | +| Login | | +| Register | | +| User | | +| Home | 13521104 | +| Daftar Lagu | 13521104 | +| Tambah Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Daftar Album | 13521104 | +| Tambah Album | 13521104 | +| Edit Album | 13521104 | +| Music Player | 13521104 | +| Search | 13521104 | +| Sort dan Filter | 13521104 | +| Card List | 13521104 | +| Album List | 13521104 | +| Navigation Bar | 13521104 | +| Pagination | 13521104 | + +### _Server Side_ + +| Fitur | NIM | +| ------------------------ | -------- | +| Login | | +| Register | | +| Home | 13521104 | +| Daftar Album | 13521104 | +| Search | 13521104 | +| Sort dan Filter | | +| Daftar Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Daftar Album | 13521104 | +| Edit Album | 13521104 | +| Tambah Lagu | 13521104 | +| Tambah Album | 13521104 | +| Pagination | | + +### _Client Side_ + +| Fitur | NIM | +| ------------------------ | -------- | +| Login | | +| Register | | +| User | | +| Home | 13521104 | +| Music Player | 13521104 | +| Daftar Album | 13521104 | +| Search | 13521104 | +| Sort dan Filter | | +| Daftar Lagu | 13521104 | +| Tambah Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Hapus Lagu | 13521104 | +| Tambah Album | 13521104 | +| Daftar Album | 13521104 | +| Edit Album | 13521104 | +| Hapus Album | 13521104 | + +| Page | NIM | +| ------------------------ | -------- | +| Login | | +| Register | | +| User | | +| Home | 13521104 | +| Daftar Lagu | 13521104 | +| Tambah Lagu | 13521104 | +| Edit Lagu | 13521104 | +| Daftar Album | 13521104 | +| Tambah Album | 13521104 | +| Edit Album | 13521104 | + +| Component | NIM | +| ------------------------ | -------- | +| Music Player | 13521104 | +| Search | 13521104 | +| Sort dan Filter | 13521104 | +| Card List | 13521104 | +| Album List | 13521104 | +| Navigation Bar | 13521104 | +| Pagination | 13521104 | + +### _Database_ + +| Fitur | NIM | +| ------------------------ | -------- | +| User | | +| Song | 13521104 | +| Album | 13521104 | + +### _Setup_ + +| Fitur | NIM | +| ------------------------ | -------- | +| Database | | +| Docker | | +| MVC | 13521104 | diff --git a/src/app/.htaccess b/src/app/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..adf8babb11f620df15cbabc18f78d67a77d0969c --- /dev/null +++ b/src/app/.htaccess @@ -0,0 +1,4 @@ +Options -Indexes + +php_value upload_max_filesize 40M +php_value post_max_size 40M \ No newline at end of file diff --git a/src/app/components/album/AddAlbum.php b/src/app/components/album/AddAlbum.php new file mode 100644 index 0000000000000000000000000000000000000000..d8bacc5490216b283459a1d6b770cad309916330 --- /dev/null +++ b/src/app/components/album/AddAlbum.php @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/addAlbum.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <title>MagicTune</title> + <link rel="shortcut icon" href="#"> +</head> +<body> + + <?php include( __DIR__. '../../template/navbar.php' ) ?> + + <form id="fileUploadForm" method='POST' enctype="multipart/form-data"> + <div class="container-auth"> + <div class="box-auth"> + <header class="h-auth">Add Album</header> + <div class="container-input-auth"> + <label name="judul" class="label-auth">Title</label> + <input name="judul" id='songTitle' type="text" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Author</label> + <input name="penyanyi" id='songAuthor' type="text" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Year</label> + <input name="year" id='songYear' type="text" class="input-auth medium" value=<?php echo date("Y"); ?> readonly> + </div> + + <!-- <label for="fileInput">Choose a file:</label> --> + <div class="container-input-auth"> + <label class="label-auth flex">Image</label> + <input class="inputAudio" type="file" id="imageInput" name="image" accept=".jpg, .jpeg, .png"> + </div> + <!-- <button type="submit">Upload</button> --> + <button class="btn-auth bottom" type="button" id="submitFormAlbum">Upload</button> + </div> + </div> + </form> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/album.js"?>></script> +</body> \ No newline at end of file diff --git a/src/app/components/album/AlbumPage.php b/src/app/components/album/AlbumPage.php new file mode 100644 index 0000000000000000000000000000000000000000..0a918f2eca1275c31e648529f5d7b2fe773fba11 --- /dev/null +++ b/src/app/components/album/AlbumPage.php @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <!-- http://localhost:3000/WBD_1 --> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <!-- Bikin css per komponen terus Tambahin CSS disini --> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/mainPage.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/body.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/searchBar.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/mainCon.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/cardCon.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/player.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/card.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/pagination.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/button.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/filter.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/album.css"?>> + <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet"> + <link href="https://fonts.googleapis.com/css2?family=Lato&display=swap" rel="stylesheet"> + <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous"> + <script type='application/javascript'>var dataDummyAlbum = <?php echo json_encode($this->data);?>;</script> + + <title>MagicTune</title> + <link rel="shortcut icon" href="#"> +</head> +<body> + <div class='mainPage'> + <?php include( __DIR__. '../../template/navbar.php' ) ?> + + <div class="mainCon"> + <!-- <div class="search-container"> + <input type="text" name="search" placeholder="Search..." onchange="handleSubmit(this.value)" class="search-input"> + <a href="#" class="search-btn"> + <i class="fas fa-search"></i> + </a> + </div> --> + + <div class="cardCon albumCon"> + + <!-- <div class="filterCon"> + <h2 class="searchText">Album List </h2> + </div> --> + <div id='reload'> + <?php include( __DIR__. '/../template/albumList.php') ?> + </div> + </div> + </div> + + </div> + + <script type="application/javascript" src=<?php echo BASEURL."/Controller/album.js"?>></script> + <!-- <script type="application/javascript" src="./Controller/controller.js"?></script> + <script type="application/javascript" src="./Controller/controllerPlayer.js"?></script> + <script type="application/javascript" src="./Controller/searchController.js"?></script> --> + <script type='application/javascript'></script>; + + + </script>" + <script type="application/javascript" src=<?php echo BASEURL."/Controller/pagination.js";?>></script> + +</body> +</html> \ No newline at end of file diff --git a/src/app/components/album/EditAlbum.php b/src/app/components/album/EditAlbum.php new file mode 100644 index 0000000000000000000000000000000000000000..03da7b12813a2e3f15811fadf79974889d8a8bad --- /dev/null +++ b/src/app/components/album/EditAlbum.php @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <!-- <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> --> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/addAlbum.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <title>MagicTune</title> + <link rel="shortcut icon" href="#"> +</head> +<body> + + <?php include( __DIR__. '../../template/navbar.php' ) ?> + + <form id="fileUploadFormEdit" method='POST' enctype="multipart/form-data"> + <div class="container-auth"> + <div class="box-auth"> + <header class="h-auth">Edit Song</header> + <div class="container-input-auth"> + <label name="judul" class="label-auth">Title</label> + <input name="judul" id='songTitle' value="<?php echo $this->data->judul;?>" type="text" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Author</label> + <input name="penyanyi" id='songAuthor' type="text" value="<?php echo $this->data->penyanyi;?>" class="input-auth medium" readonly> + </div> + <div class="container-input-auth"> + <label class="label-auth">Year</label> + <input name="year" id='songYear' type="text" value="<?php echo $this->data->year;?>" class="input-auth medium" readonly> + </div> + + <div class="container-input-auth"> + <label class="label-auth flex">Image</label> + <input name="old_image" id='songAudio' type="text" value="<?php echo $this->data->image;?>" class="input-auth medium file" readonly> + <input class="inputAudio" type="file" id="imageInput" name="image" accept=".jpg, .jpeg, .png"> + </div> + <button class="btn-auth bottom" type="button" id="submitFormEdit">Upload</button> + </div> + </div> + </form> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/album.js"?>></script> +</body> \ No newline at end of file diff --git a/src/app/components/auth/SignIn.php b/src/app/components/auth/SignIn.php new file mode 100644 index 0000000000000000000000000000000000000000..218c555ad4af521e40d33815e921b388d2c829eb --- /dev/null +++ b/src/app/components/auth/SignIn.php @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> + <link rel="stylesheet" href="./../../../public/Resources/Styles/login.css"> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <script type="text/javascript" src="../../../public/Controller/signInController.js"></script> +</head> +<body> +<?php include( __DIR__. '../../template/navbar.php' ) ?> + <div class="container-auth"> + <form class="box-auth", id="form-auth"> + <div><header class="h-auth">Sign in</header></div> + <div class="container-input-auth"> + <label id="emailLabel" class="label-auth">Email</label> + <input id="email" type="email" class="input-auth medium"> + + </div> + <div class="container-input-auth"> + <label class="label-auth">Password</label> + <input id="password" type="password" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <p class="fade"> <a href="<?=BASEURL?>/auth/signup">Belum punya akun?</a></p> + </div> + <button id="signButton" type="submit" class="btn-auth bottom">Sign In</button> + </form> + + </div> +</body> \ No newline at end of file diff --git a/src/app/components/auth/SignUp.php b/src/app/components/auth/SignUp.php new file mode 100644 index 0000000000000000000000000000000000000000..f02a9a6315cde90046880aed2566c8bcee4ea376 --- /dev/null +++ b/src/app/components/auth/SignUp.php @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> + <link rel="stylesheet" href="./../../../public/Resources/Styles/login.css"> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <script type="text/javascript" src="../../../public/Controller/signUpController.js"></script> +</head> +<body> +<?php include( __DIR__. '../../template/navbar.php' ) ?> + <div class="container-auth"> + <form class="box-auth" id="form-auth"> + <header class="h-auth">Sign up</header> + <div class="container-input-auth"> + <label class="label-auth">Username</label> + <input type="text" class="input-auth medium" id="username"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Email</label> + <input type="email" class="input-auth medium" id="email"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Password</label> + <input type="password" class="input-auth medium" id="password"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Confirm Password</label> + <input type="password" class="input-auth medium" id="confirm"> + </div> + <button type="submit" class="btn-auth bottom" id=signButton>Sign up</button> + </form> + + </div> +</body> \ No newline at end of file diff --git a/src/app/components/home/HomePage.php b/src/app/components/home/HomePage.php new file mode 100644 index 0000000000000000000000000000000000000000..23c943d99bd00cc5ef68bdf1967e986ec2b38833 --- /dev/null +++ b/src/app/components/home/HomePage.php @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <!-- http://localhost:3000/WBD_1 --> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <!-- Bikin css per komponen terus Tambahin CSS disini --> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/mainPage.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/body.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/searchBar.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/mainCon.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/cardCon.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/player.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/card.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/pagination.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/button.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/filter.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/album.css"?>> + <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet"> + <link href="https://fonts.googleapis.com/css2?family=Lato&display=swap" rel="stylesheet"> + <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous"> + <script type='application/javascript'>var dataDummy = <?php echo json_encode($this->data[0]);?>;</script> + + <title>MagicTune</title> + <link rel="shortcut icon" href="#"> +</head> +<body> + <div class='mainPage'> + <?php include( __DIR__. '../../template/navbar.php' ) ?> + + <div class="mainCon"> + <div class="search-container"> + <input id="searchBar" type="text" name="search" placeholder="Search..." class="search-input"> + <a class="search-btn"> + <i class="fas fa-search"></i> + </a> + </div> + + <div class="cardCon"> + <div class="filterCon"> + <h2 class="searchText">Now Playing : </h2> + <?php include( __DIR__. '/../template/filter.php') ?> + </div> + <div id='reload'> + <?php include( __DIR__. '/../template/cardList.php') ?> + </div> + </div> + <div class='playerCon'> + <div class='progressBar'> + + </div> + <div class="player"> + <div class="sliderPlayerCon"> + <div class="slider_container"> + <div class="current-time">00:00</div> + <input type="range" min="1" max="100" + value="0" class="seek_slider" onchange="seekTo()"> + <div class="total-duration">00:00</div> + </div> + <div class="buttonCon"> + <div class="prev-track" onclick="prevTrack()"> + <i class="fa fa-step-backward fa-2x"></i> + </div> + <div class="playpause-track" onclick="playpauseTrack()"> + <i class="fa fa-play-circle fa-5x"></i> + </div> + <div class="next-track" onclick="nextTrack()"> + <i class="fa fa-step-forward fa-2x"></i> + </div> + </div> + </div> + </div> + </div> + </div> + + </div> + + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/controller.js"?>></script> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/controllerPlayer.js"?>></script> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/song.js"?>></script> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/debounce.js"?>></script> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/pagination.js"?>></script> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/search.js"?>></script> + +</body> +</html> \ No newline at end of file diff --git a/src/app/components/not-found/NotFoundPage.php b/src/app/components/not-found/NotFoundPage.php new file mode 100644 index 0000000000000000000000000000000000000000..13fba2513de7c4c39a79e095586b5606206898ba --- /dev/null +++ b/src/app/components/not-found/NotFoundPage.php @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Page not found!</title> +</head> + +<body> + +</body> + +</html> \ No newline at end of file diff --git a/src/app/components/song/AddSong.php b/src/app/components/song/AddSong.php new file mode 100644 index 0000000000000000000000000000000000000000..1ebf6a96c098699206333420ca21ede4380ef0a4 --- /dev/null +++ b/src/app/components/song/AddSong.php @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/addSong.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <title>MagicTune</title> + <link rel="shortcut icon" href="#"> +</head> +<body> + + <?php include( __DIR__. '../../template/navbar.php' ) ?> + + <form id="fileUploadForm" method='POST' enctype="multipart/form-data"> + <div class="container-auth"> + <div class="box-auth"> + <header class="h-auth">Add Song</header> + <div class="container-input-auth"> + <label name="judul" class="label-auth">Title</label> + <input name="judul" id='songTitle' type="text" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Author</label> + <input name="penyanyi" id='songAuthor' type="text" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Year</label> + <input name="year" id='songYear' type="text" class="input-auth medium" value=<?php echo date("Y"); ?> readonly> + </div> + <div class="container-input-auth flex"> + <label class="label-auth">Album</label> + <select name="album_id" id="option" value=""> + <option selected value="undef"> -- select an option -- </option> + <?php + // Sample data array (you can replace this with your data source) + $options = $this->data; + + // Loop through the data to generate dropdown options + foreach ($options as $key) { + echo '<option value="' . ($key['album_id']) . '">' . $key['judul'] . '</option>'; + } + ?> + </select> + </div> + + <!-- <label for="fileInput">Choose a file:</label> --> + <div class="container-input-auth"> + <label class="label-auth flex">Audio</label> + <input class="inputAudio" type="file" id="audioInput" name="audio" accept=".mp3"> + </div> + <div class="container-input-auth"> + <label class="label-auth flex">Image</label> + <input class="inputAudio" type="file" id="imageInput" name="image" accept=".jpg, .jpeg, .png"> + </div> + <!-- <button type="submit">Upload</button> --> + <button class="btn-auth bottom" type="button" id="submitForm">Upload</button> + </div> + </div> + </form> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/song.js"?>></script> +</body> \ No newline at end of file diff --git a/src/app/components/song/EditSong.php b/src/app/components/song/EditSong.php new file mode 100644 index 0000000000000000000000000000000000000000..7595fe5dc097cad19bd12ac231fe0cc6c8bbab05 --- /dev/null +++ b/src/app/components/song/EditSong.php @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <!-- <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> --> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/addSong.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <title>MagicTune</title> + <link rel="shortcut icon" href="#"> +</head> +<body> + + <?php include( __DIR__. '../../template/navbar.php' ) ?> + + <form id="fileUploadFormEdit" method='POST' enctype="multipart/form-data"> + <div class="container-auth"> + <div class="box-auth editAlbum"> + <header class="h-auth">Edit Song</header> + <div class="container-input-auth"> + <label name="judul" class="label-auth">Title</label> + <input name="judul" id='songTitle' type="text" value="<?php echo $this->data["judul"]; ?>"" class="input-auth medium"> + </div> + <div class="container-input-auth"> + <label class="label-auth">Author</label> + <input name="penyanyi" id='songAuthor' type="text" value="<?php echo $this->data["penyanyi"]; ?>" class="input-auth medium" readonly> + </div> + <div class="container-input-auth"> + <label class="label-auth">Year</label> + <input name="year" id='songYear' type="text" class="input-auth medium" value=<?php echo date("Y"); ?> readonly> + </div> + <div class="container-input-auth flex"> + <label class="label-auth">Album</label> + <input name="album_id" id='songAlbum' type="text" class="input-auth medium" value="<?php echo $this->data["judul_album"];?>" readonly> + </div> + + <div class="container-input-auth"> + <label class="label-auth flex">Audio</label> + <input name="old_audio" id='songAudio' type="text" class="input-auth medium file" value="<?php echo $this->data["audio"];?>" readonly> + <input class="inputAudio" type="file" id="audioInput" name="audio" accept=".mp3"> + </div> + <div class="container-input-auth"> + <label class="label-auth flex">Image</label> + <input name="old_image" id='songAudio' type="text" class="input-auth medium file" value="<?php echo $this->data["image"];?>" readonly> + <input class="inputAudio" type="file" id="imageInput" name="image" accept=".jpg, .jpeg, .png"> + </div> + <button class="btn-auth bottom" type="button" id="submitFormEdit">Upload</button> + </div> + </div> + </form> + <script type="application/javascript" src=<?php echo BASEURL."/Controller/song.js"?>></script> +</body> \ No newline at end of file diff --git a/src/app/components/template/SongList.php b/src/app/components/template/SongList.php new file mode 100644 index 0000000000000000000000000000000000000000..c2a218bb48c5bfccebe318f1663650d9fd7aad08 --- /dev/null +++ b/src/app/components/template/SongList.php @@ -0,0 +1,31 @@ +<?php +$count=0 + +?> + +<div class="cardCon2"> + <div class="cardCon3" id="data-container"> + <?php + if($this->data !== null){ + foreach ($this->data[0] as $item) { + echo '<div class="card" id="song'.$item["song_id"].'">'; + echo '<img class="cardIMG" src="http://localhost:8080/storage/images/'.$item["image"].'">'; + echo '<h2 class="cardTitle">'.$item["judul"].'</h2>'; + echo '<h4 class="cardAuthor">'.$item["penyanyi"].'</h4>'; + echo '<h5 class="cardAuthor">'.$item["year"].'</h5>'; + echo '<div class="cardButtonCon">'; + echo '<div onClick=deleteSong('.$count.') class="playButton delete"></div>'; + echo '<a href="/public/song/edit/'.$item["song_id"].'"><div class="playButton edit"></div></a>'; + echo "<div onclick=playStopClick(" . $count . ") id=\"" . $count . "\"class=\"playButton\"></div>"; + echo '</div>'; + echo '</div>'; + $count=$count+1; + } + } + ?> + </div> + <div class="paginationCon" id='scroll'> + <?php include( __DIR__.'/pagination.php') ?> + </div> +</div> + diff --git a/src/app/components/template/albumList.php b/src/app/components/template/albumList.php new file mode 100644 index 0000000000000000000000000000000000000000..65327244fe892a3c7d0885bad05268793a8e95fd --- /dev/null +++ b/src/app/components/template/albumList.php @@ -0,0 +1,40 @@ +<?php + $count=0 + +?> + +<div class="cardCon2"> + + <div class="cardCon3 albumCon"> + <?php + if($this->data !== null){ + foreach ($this->data as $item) { + echo '<div class="card">'; + echo '<img class="cardIMG" src="http://localhost:8080/storage/images/'.$item["image"].'">'; + echo '<h2 class="cardTitle">'.$item["judul"].'</h2>'; + // echo '<div class="albumFlexCon">'; + echo '<h4 class="cardAuthor">'.$item["penyanyi"].'</h4>'; + echo '<h5 class="cardAuthor">'.$item["year"].'</h5>'; + // echo '</div>'; + echo '<div class="cardButtonCon">'; + echo '<div onClick=deleteAlbum('.$count.') class="playButton delete"></div>'; + echo '<a href="/public/album/edit/'.$item["album_id"].'"><div class="playButton edit"></div></a>'; + // echo '<div onclick=playStopClick('.$count.') id="'.$count.'"class="playButton"></div>'; + echo '</div>'; + echo '</div>'; + $count=$count+1; + } + } + ?> + <div class="outerCard"> + <div class="card addAlbum"> + <a href="/public/album/add"> + <img class="addAlbumIMG" src=<?php echo'"'.BASEURL.'/Resources/Assets/Logo/addAlbum.png"';?>> + </a> + </div> + </div> + </div> + <div class="paginationCon" id='scroll'> + <?php include( __DIR__.'/pagination.php') ?> + </div> + </div> \ No newline at end of file diff --git a/src/app/components/template/cardList.php b/src/app/components/template/cardList.php new file mode 100644 index 0000000000000000000000000000000000000000..11bd177f55692a48e3cbac6f4e7baca32c18c9ab --- /dev/null +++ b/src/app/components/template/cardList.php @@ -0,0 +1,32 @@ +<?php + $count=0 + +?> + +<div class="cardCon2"> + <div class="cardCon3" id="data-container"> + <?php + if($this->data !== null){ + foreach ($this->data[0] as $item) { + echo '<div class="card" id="song'.$item["song_id"].'">'; + echo '<img class="cardIMG" src="http://localhost:8080/storage/images/'.$item["image"].'">'; + echo '<h2 class="cardTitle">'.$item["judul"].'</h2>'; + echo '<h4 class="cardAuthor">'.$item["penyanyi"].'</h4>'; + echo '<h5 class="cardAuthor">'.$item["year"].'</h5>'; + + echo '<div class="cardButtonCon">'; + echo '<div onClick=deleteSong('.$count.') class="playButton delete"></div>'; + echo '<a href="/public/song/edit/'.$item["song_id"].'"><div class="playButton edit"></div></a>'; + echo '<div onclick=playStopClick('.$count.') id="'.$count.'"class="playButton"></div>'; + echo '</div>'; + echo '</div>'; + $count=$count+1; + } + } + ?> + </div> + <div class="paginationCon" id='scroll'> + <?php include( __DIR__.'/pagination.php') ?> + </div> + </div> + diff --git a/src/app/components/template/filter.php b/src/app/components/template/filter.php new file mode 100644 index 0000000000000000000000000000000000000000..78db129e4fa1e2e1e81b228ee3a060b05b296964 --- /dev/null +++ b/src/app/components/template/filter.php @@ -0,0 +1,16 @@ +<div class="filterCon2"> + <div id='filterTitle' onClick="changeValue('filterTitle')" value="DESCENDING" class="filter" ><h3 class="filterText">Title</h3><i class="fas fa-sort"></i></div> + <div id='filterYear' onClick="changeValue('filterYear')" value="DESCENDING" class="filter" ><h3 class="filterText">Year</h3><i class="fas fa-sort"></i></div> + <select id='filterAlbum' class="filter" name="album_id" id="option" value=""> + <option selected value="undef"><h3 class="filterText">Album</h3></option> + <?php + // Sample data array (you can replace this with your data source) + $options = $this->data[1]; + + // Loop through the data to generate dropdown options + foreach ($options as $key) { + echo '<option value="' . ($key['album_id']) . '">' . $key['judul'] . '</option>'; + } + ?> + </select> + </div> diff --git a/src/app/components/template/navbar.php b/src/app/components/template/navbar.php new file mode 100644 index 0000000000000000000000000000000000000000..e1e1644a5804ed0d7fa2a2bd14c66009d2f9028b --- /dev/null +++ b/src/app/components/template/navbar.php @@ -0,0 +1,27 @@ +<div class="navCon"> + <nav class='navbar'> + <a class="logoCon" href="/public/"> + <img class='logoimg' src=<?php echo'"'.BASEURL.'/Resources/Assets/Logo/logo.png"';?>> + </a> + <div class='leftCon'> + <a class="" href="/public/album/index"> + <img class='navbarimg' src=<?php echo'"'.BASEURL.'/Resources/Assets/Logo/album.png"';?>> + </a> + <a class="" href="/public/song/add"> + <img class='navbarimg' src=<?php echo'"'.BASEURL.'/Resources/Assets/Logo/addSong.png"';?>> + </a> + </div> + + <a href="<?php + if(isset($_SESSION['user_id'])){ + echo BASEURL . "/user"; + }else{ + echo BASEURL . "/auth"; + } + ?>"> + <div class="avatar"> + <div class="user-icon"><span></span></div> + </div> + </a> + </nav> +</div> \ No newline at end of file diff --git a/src/app/components/template/pagination.php b/src/app/components/template/pagination.php new file mode 100644 index 0000000000000000000000000000000000000000..5ee55db9685a322e4983c099e649b95dcd4c4d25 --- /dev/null +++ b/src/app/components/template/pagination.php @@ -0,0 +1,8 @@ +<?php +// <div class="pagination"> +// <div class="button1 active"></div> +// <div class="button1"></div> +// <div class="button1"></div> +// <div class="button1"></div> +// <div class="button1"></div> +// </div> \ No newline at end of file diff --git a/src/app/components/user/AdminPage.php b/src/app/components/user/AdminPage.php new file mode 100644 index 0000000000000000000000000000000000000000..9fc94e3db838305029af54cb29e58c1da7f4d073 --- /dev/null +++ b/src/app/components/user/AdminPage.php @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/cardCon.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/userPage.css"?>> + <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> + <title>Admin Page</title> +</head> +<body> + <div class="admin-page"> + <?php include(__DIR__."/../template/navbar.php")?> + <div class="blue-container"> + <?php + if (empty($this->data)) { + echo '<tabel class="user-tabel"> + <tr> + <th>User Id</th> + <th>Username</th> + <th>Email</th> + <th>Nama</th> + </tr>'; + foreach ($this->data as $song) { + echo '<tr> + <td>'.$song->user_id.'</td> + <td>'.$song->username.'</td> + <td>'.$song->email.'</td> + <td>'.$song->fullname.'</td> + </tr>'; + } + echo '</tabel>'; + } + else { + echo '<h1 class="data-empty">Tidak ada data data</h1>'; + } + ?> + </div> + </div> +</body> +</html> diff --git a/src/app/components/user/userPage.php b/src/app/components/user/userPage.php new file mode 100644 index 0000000000000000000000000000000000000000..bcbfdd150eb3a465f8e333d3dbe4b9615f475858 --- /dev/null +++ b/src/app/components/user/userPage.php @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/navbar.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/cardCon.css"?>> + <link rel="stylesheet" href=<?php echo BASEURL."/Resources/Styles/userPage.css"?>> + <link href='https://fonts.googleapis.com/css?family=Prompt' rel='stylesheet'> + <title>User Page</title> +</head> +<body> + <div class="user-page"> + <?php include(__DIR__."/../template/navbar.php")?> + + <h2>Pengaturan Pengguna</h2> + + <div class="blue-container"> + <div class="photo-profile-box"> + <img class="photo-profile" src="<?=$this->data->photo_profile?>" alt="Photo-Profile"> + <button type="submit" class="button white-button">Ubah foto</button> + </div> + <div class="user-change-info"> + <form class="form-change full-name-change"> + <div class="left-column"> + <label for="full-name">Name</label> + <input type="text" id="full-name" placeholder="Enter your full name here"> + <p class="alert-hide-show" id="alert-username">nama tidak bisa kosong!</p> + </div> + <button id="full-name-btn" type="submit" class="button white-button btn-approve">Ubah Nama</button> + </form> + <form class="form-change username-change"> + <div class="left-column"> + <label for="username">Username</label> + <input type="text" id="username" placeholder="change Username here"> + <p class="alert-hide-show" id="alert-username">usernname sudah digunakan!</p> + </div> + <button id="username-btn" type="submit" class="button white-button btn-approve">Ubah Username</button> + </form> + <form class="form-change email-change"> + <div class="left-column"> + <label for="email">Email</label> + <input type="email" id="email" placeholder="change Email here"> + <p class="alert-hide-show" id="alert-email">email sudah digunakan!</p> + </div> + <button id="email-btn" type="submit" class="button white-button btn-approve">Ubah Email</button> + </form> + <form class="form-change password-change"> + <div class="left-column"> + + <div class="input-password-field"> + <label for="password">Password</label> + <input type="text" id="password" placeholder="Change your Password"> + </div> + <div class="input-confirm-password-field"> + <label for="confirm-password">Confirm Password</label> + <input type="text" id="confirm-password" placeholder="Confirm your new Password"> + </div> + + <p class="alert-hide-show" id="alert-password">password tidak sesuai!</p> + </div> + <button id="password-btn" type="submit" class="button white-button btn-approve">Ubah Password</button> + </form> + </div> + <div class="user-info"> + <p class="attribute">Name</p> + <p class="content"><?=$this->data->user_data->fullname?></p> + <p class="attribute">Username</p> + <p class="content"><?=$this->data->user_data->username?></p> + <p class="attribute">Email</p> + <p class="content"><?=$this->data->user_data->email?></p> + </div> + </div> +<!-- <h2>Your Song</h2>--> +<!-- --><?php //include(__DIR__."/../template/cardList.php")?> + </div> +</body> +</html> \ No newline at end of file diff --git a/src/app/config/config.php b/src/app/config/config.php new file mode 100644 index 0000000000000000000000000000000000000000..05b70de38a9cf5b1cd0beed83d466e0f30a8b611 --- /dev/null +++ b/src/app/config/config.php @@ -0,0 +1,52 @@ +<?php + + +// URL +define('BASEURL','http://localhost:8080/public'); +define('STORAGE_URL', 'http://localhost:8080/storage'); + +// Database +$ENV['POSTGRES_HOST'] = "db-tubes-1"; +$ENV['POSTGRES_DB'] = "magictune"; +$ENV['POSTGRES_USER'] = "utubes1"; +$ENV['POSTGRES_PASSWORD'] = "admintubes"; +$ENV['POSTGRES_PORT'] = "5432"; + +define('HOST', $ENV['POSTGRES_HOST']); +define('DBNAME', $ENV['POSTGRES_DB']); +define('USER', $ENV['POSTGRES_USER']); +define('PASSWORD', $ENV['POSTGRES_PASSWORD']); +define('PORT', $ENV['POSTGRES_PORT']); +define('ROWS_PER_PAGE', 10); // Application Logic + +// File +define('MAX_SIZE', 40 * 1024 * 1024); +// define('ALLOWED_AUDIOS', [ +// 'audio/mpeg' => '.mp3' +// ]); + +define('ALLOWED_AUDIOS', [ + 'audio/mpeg' => '.mp3', + 'audio/wav' => '.wav', + 'audio/ogg' => '.ogg', + 'audio/aac' => '.aac', + 'audio/flac' => '.flac', + // Add more audio formats here as needed +]); +define('ALLOWED_IMAGES', [ + 'image/jpeg' => '.jpeg', + 'image/jpg' => '.jpg', + 'image/png' => '.png' +]); + +// Bcrypt +define('BCRYPT_COST', 10); + +// Session +define('COOKIES_LIFETIME', 24 * 60 * 60); +define('SESSION_EXPIRATION_TIME', 24 * 60 * 60); +define('SESSION_REGENERATION_TIME', 30 * 60); +define('MAX_SONG_COUNT', 3); // Application Logic + +// Debounce +define('DEBOUNCE_TIMEOUT', 500); diff --git a/src/app/controllers/AdminController.php b/src/app/controllers/AdminController.php new file mode 100644 index 0000000000000000000000000000000000000000..f6b095e9a258a3d116c74aeab6a7485bd5f8ac40 --- /dev/null +++ b/src/app/controllers/AdminController.php @@ -0,0 +1,29 @@ +<?php +class AdminController extends Controller implements ControllerInterface +{ + public function index() + { + try { + switch($_SERVER['REQUEST_METHOD']) { + case 'GET': + $data = new stdClass(); + + $admin_model = $this->model('AdminModel'); + $data = $admin_model->getAllUsers(); + var_dump($data); + $homeView=$this->view('user','AdminView', $data); + $homeView->render(); + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } + catch (Exception $e) { + http_response_code($e->getCode()); + } + // Need to check first whether session exists, then proceed + //if not exists, redirect to login page + // $user_data = $this->model('UserModel')->getUserFromId($_SESSION['user_id']); + } +} +?> \ No newline at end of file diff --git a/src/app/controllers/AlbumController.php b/src/app/controllers/AlbumController.php new file mode 100644 index 0000000000000000000000000000000000000000..260203a831c5c8d8f5121258cc9ecb76e70e9ebf --- /dev/null +++ b/src/app/controllers/AlbumController.php @@ -0,0 +1,138 @@ +<?php + +class AlbumController extends Controller implements ControllerInterface +{ + public function index() + { + $AlbumModel = $this->model('AlbumModel'); + $temp = $AlbumModel->getAllAlbum(); + $jsonData = json_decode(json_encode($temp), true); + + $albumView=$this->view('album','AlbumView',$jsonData); + $albumView->render(); + + + } + public function add() + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + // Load AddAlbumView.php + $addAlbumView = $this->view('album', 'AddAlbumView'); + $addAlbumView->render(); + exit; + + break; + case 'POST': + // Halaman hanya bisa diakses admin + + /* Lakukan validasi */ + // Form tidak lengkap + if (!$_POST['judul'] || !$_POST['penyanyi'] || !$_POST['year']) { + throw new LoggedException('Bad Request', 400); + } + // File tidak diisi + if ($_FILES['image']['error'] === 4) { + throw new LoggedException('Bad Request', 400); + } + + $storageAccessImage = new StorageAccess(StorageAccess::IMAGE_PATH); + $uploadedImage = $storageAccessImage->saveImage($_FILES['image']['tmp_name']); + + $albumModel = $this->model('AlbumModel'); + $albumModel->addAlbum($_POST['judul'], $_POST['penyanyi'] , $_POST['year'], $uploadedImage); + + // header("Location: /public/album/detail/$albumID", true, 301); + exit; + + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + if ($e->getCode() == 401) { + /* Unauthorized */ + $notFoundView = $this->view('not-found', 'NotFoundView'); + $notFoundView->render(); + } + http_response_code($e->getCode()); + exit; + } + } + public function delete() + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'POST': + // Halaman hanya bisa diakses admin + + // Hapus dari storage + $storageAccessImage = new StorageAccess(StorageAccess::IMAGE_PATH); + $storageAccessImage->deleteFile($_POST['image']); + + // Hapus dari database + $albumModel = $this->model('AlbumModel'); + $albumModel->deleteAlbum($_POST['album_id']); + + // Kirimkan response + exit; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + exit; + } + } + + + public function edit($params) + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + // Prevent CSRF Attacks + + + $albumID = (int) $params; + + $albumModel = $this->model('AlbumModel'); + $albumData = $albumModel->getAlbumFromID($albumID); + + $albumEditView = $this->view('album', 'EditAlbumView', $albumData); + + $albumEditView->render(); + + exit; + + break; + case 'POST': + + if (!$_POST['judul'] || !$_POST['penyanyi'] || !$_POST['year']) { + throw new LoggedException('Bad Request', 400); + } + + $albumModel = $this->model('AlbumModel'); + $albumID = (int)$params; + + $albumModel->changeAlbumJudul($albumID, $_POST["judul"]); + + if ($_FILES['image']['error'] !== 4) { + $storageAccessImage = new StorageAccess(StorageAccess::IMAGE_PATH); + $storageAccessImage->deleteFile($_POST['old_image']); + $uploadedImage = $storageAccessImage->saveImage($_FILES['image']['tmp_name']); + $albumModel->changeAlbumImage($albumID, $uploadedImage); + } + + exit; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + exit; + } + } + +} \ No newline at end of file diff --git a/src/app/controllers/AuthController.php b/src/app/controllers/AuthController.php new file mode 100644 index 0000000000000000000000000000000000000000..98ff775efb2a2344fd13edf9b6d1a8cb998449dc --- /dev/null +++ b/src/app/controllers/AuthController.php @@ -0,0 +1,173 @@ +<?php +/** + * TODO + * 1. create login feature + * 2. Handle page switching + */ + +class AuthController extends Controller implements ControllerInterface{ + + public function index() + { + try{ + //initialize session + session_start(); + + //check if session exist + $signed_in = isset($_SESSION["signed_in"]) ? $_SESSION["signed_in"] : false; + if($signed_in){ + //session exist, proceed to redirect to home + $path = BASEURL . ""; + header("location:" . $path); + exit; + }else{ + echo "<script>console.log('apue')</script>"; + } + //session not exist, proceed to render loginpage + $data['profile_pic'] = ""; + $homeView=$this->view('auth','SignInView', $data); + $homeView->render(); + // $this->view('auth','SignInView', $data); + }catch(Exception $e){ + http_response_code($e->getCode()); + exit; + } + } + + public function signin(){ + try{ + switch($_SERVER['REQUEST_METHOD']){ + case 'POST': + //create response array + $response = array(); + $model = $this->model("AuthModel"); + + //validate + + $user_id = $model->signin($_POST['email'], $_POST['password']); + + //input validated, create session and redirect + session_start(); + + $_SESSION['user_id'] = $user_id; + $_SESSION['signed_in'] = true; + + //redirect + + $response['success'] = true; + + $response['redirect'] = BASEURL; + http_response_code(201); + header("Content-Type: application/json"); + echo json_encode($response);//does response need to be destroyed? It is destroyed automatically. + + exit; + case 'GET': + $homeView=$this->view('auth','SignInView', null); + $homeView->render(); + default: + throw new LoggedException('Method Not Allowed', 405); + } + + }catch (Exception $e){ + http_response_code($e->getCode()); + exit; + } + } + + public function signup(){ + try{ + //no validation yet + switch($_SERVER['REQUEST_METHOD']){ + case 'POST': + + $response = array(); + //check if username or email exist + + $model = $this->model("AuthModel"); + + $response['usernameError'] = false; + $response['emailError'] = false; + if($model->isUsernameExist($_POST['username'])){ + $response['usernameError'] = true; + } + + + if($model->isEmailExist($_POST['email'])){ + $response['emailError'] = true; + } + + + //if error + + if($response['emailError'] || $response['usernameError']){ + http_response_code(409); + }else{ + http_response_code(201); + + $model->signup($_POST['email'], $_POST['username'], "Mas JOjo",$_POST['password'], false);// replace fullname, dont forget. + $response['redirect_url'] = BASEURL . ""; + } + + //if not proceed to insert to database and redirect to login + header("Content-Type: application/json"); + echo json_encode($response);// this method still tighly coupled + // http_response_code(205); + // exit; + exit; + case 'GET': + $homeView=$this->view('auth','SignUpView', null); + $homeView->render(); + default: + throw new LoggedException('Method Not Allowed', 405); + + } + }catch(Exception $e){ + http_response_code($e->getCode()); + exit; + } + } + public function signout(){ + try{ + // Initialize the session + session_start(); + + // Unset all of the session variables + $_SESSION = array(); + + // Destroy the session. + session_destroy(); + + // Redirect to login page + header("location: login.php"); + exit; + }catch(Exception $e){ + http_response_code($e->getCode()); + exit; + } + } + + /** + * Check whether the user is signed in + * return boolean + */ + public function isSignedIn(){ + + session_start(); + isset($_SESSION["signed_in"]) ? $_SESSION["signed_in"] : false; + return true; + } + public function isSignedInRequest(){ + try{ + $response = array(); + if(isSignedIn()){ + $response["signed_in"] =true; + }else{ + $response["signed_in"] = false; + } + }catch(Exception $e){ + http_response_code($e->getCode()); + exit; + } + } +} \ No newline at end of file diff --git a/src/app/controllers/HomeController.php b/src/app/controllers/HomeController.php new file mode 100644 index 0000000000000000000000000000000000000000..c43e46965ff1133d4629bf8a591f73301f4d9984 --- /dev/null +++ b/src/app/controllers/HomeController.php @@ -0,0 +1,75 @@ +<?php + +class HomeController extends Controller implements ControllerInterface +{ + public function index() + { + + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + $songModel = $this->model('SongModel'); + $albumModel = $this->model('AlbumModel'); + $temp = $songModel->getAllSongs(); + $tempAlbum = $albumModel->getAllAlbum(); + $jsonData = json_decode(json_encode($temp), true); + $jsonDataAlbum = json_decode(json_encode($tempAlbum), true); + $homeView=$this->view('home','MainView',[$jsonData,$jsonDataAlbum]); + $homeView->render(); + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + } + + } + public function fetch($page) + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + + $songModel = $this->model('SongModel'); + $songArr = $songModel->getByQuery($_GET['q'], $_GET['sort'], $_GET['filter'], $page); + + header('Content-Type: application/json'); + echo json_encode($songArr); + exit; + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + exit; + } + } + + public function search() + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + header('Content-Type: application/json'); + $q = ''; + if (isset($_GET['q'])) { + $q = $_GET['q']; + } + $songModel = $this->model('SongModel'); + $songArr = $songModel->getByQuery($q); + + + // Encode the data as JSON and send it as the response. + echo json_encode(["data" => $songArr]); + exit; + + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + } + } +} \ No newline at end of file diff --git a/src/app/controllers/NotFoundController.php b/src/app/controllers/NotFoundController.php new file mode 100644 index 0000000000000000000000000000000000000000..cb6d9d8f7b1d559489e0211d36d9d8a53a4e1759 --- /dev/null +++ b/src/app/controllers/NotFoundController.php @@ -0,0 +1,10 @@ +<?php + +class NotFoundController extends Controller implements ControllerInterface +{ + public function index() + { + $notFoundView = $this->view('not-found', 'NotFoundView'); + $notFoundView->render(); + } +} diff --git a/src/app/controllers/SongController.php b/src/app/controllers/SongController.php new file mode 100644 index 0000000000000000000000000000000000000000..93817fe016fa045bfc0f9daafba4db1620d28cb7 --- /dev/null +++ b/src/app/controllers/SongController.php @@ -0,0 +1,198 @@ +<?php + +class SongController extends Controller implements ControllerInterface +{ + public function index() + { + $notFoundView = $this->view('not-found', 'NotFoundView'); + $notFoundView->render(); + } + + + public function add() + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + + // Get Album ID + $albumModel = $this->model('AlbumModel'); + $temp = $albumModel->getAllAlbum(); + $albumArr = json_decode(json_encode($temp), true); + + // Load AddSongView.php + $addSongView = $this->view('song', 'AddSongView', $albumArr); + $addSongView->render(); + exit; + + break; + case 'POST': + + if (!$_POST['judul'] || !$_POST['penyanyi'] || !$_POST['year'] || !$_POST['album_id']) { + throw new LoggedException('Bad Request', 400); + } + // File tidak diisi + if ($_FILES['audio']['error'] === 4 || $_FILES['image']['error'] === 4) { + throw new LoggedException('Bad Request', 400); + } + //validasi album + if ($_POST['album_id'] !== "undef") { + $albumModel = $this->model('AlbumModel'); + $album = $albumModel->getAlbumFromID($_POST['album_id']); + }else{ + + } + + $storageAccessAudio = new StorageAccess(StorageAccess::SONG_PATH); + $uploadedAudio = $storageAccessAudio->saveAudio($_FILES['audio']['tmp_name']); + + $storageAccessImage = new StorageAccess(StorageAccess::IMAGE_PATH); + $uploadedImage = $storageAccessImage->saveImage($_FILES['image']['tmp_name']); + + // $uploadedAudio=STORAGE_URL.'"/songs/"'.$_POST['audio']; + // $uploadedImage=STORAGE_URL.'"/songs/"'.$_POST['image']; + $songModel = $this->model('SongModel'); + $songID = $songModel->addSong($_POST['judul'], $_POST['penyanyi'], (int) $_POST['year'], $uploadedAudio, $uploadedImage, $_POST['album_id']); + + exit; + + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + if ($e->getCode() == 401) { + /* Unauthorized */ + $notFoundView = $this->view('not-found', 'NotFoundView'); + $notFoundView->render(); + } + http_response_code($e->getCode()); + exit; + } + } + + public function delete() + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'POST': + // Hapus dari storage + // $storageAccessImage = new StorageAccess(StorageAccess::IMAGE_PATH); + // $storageAccessImage->deleteFile($_POST['image']); + + // $storageAccessAudio = new StorageAccess(StorageAccess::SONG_PATH); + // $storageAccessAudio->deleteFile($_POST['audio']); + + // Hapus dari database + $songID = (int) $_POST['song_id']; + $songModel = $this->model('songModel'); + $songModel->deleteSong($songID); + + exit; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + exit; + } + } + + public function edit($params) + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + + + $songID = (int) $params; + + $songModel = $this->model('SongModel'); + $song = $songModel->getSong($songID); + $album = $songModel->getAlbumFromSongID($songID); + if ($song) { + $song_props = [ + "song_id" => $song->song_id, "judul" => $song->judul, "penyanyi" => $song->penyanyi, + "image" => $song->image, "audio" => $song->audio, "year" => $song->year, "album_id" => $song->album_id, "judul_album" => $album->judul_album, + ]; + } else { + $song_props = []; + } + + $songEditView = $this->view('song', 'EditSongView', $song_props); + + + $songEditView->render(); + + exit; + + break; + case 'POST': + + if (!$_POST['judul'] || !$_POST['penyanyi'] || !$_POST['year']) { + throw new LoggedException('Bad Request', 400); + } + + $songModel = $this->model('SongModel'); + $songID = (int)$params; + + $songModel->changeSongTitle($songID, $_POST["judul"]); + + if ($_FILES['image']['error'] !== 4) { + $storageAccessImage = new StorageAccess(StorageAccess::IMAGE_PATH); + // $storageAccessImage->deleteFile($_POST['old_image']); + $uploadedImage = $storageAccessImage->saveImage($_FILES['image']['tmp_name']); + $songModel->changeImagePath($songID, $uploadedImage); + } + + if ($_FILES['audio']['error'] !== 4) { + $storageAccessAudio = new StorageAccess(StorageAccess::SONG_PATH); + // $storageAccessAudio->deleteFile($_POST['old_audio']); + $uploadedAudio = $storageAccessAudio->saveAudio($_FILES['audio']['tmp_name']); + $songModel->changeAudioPath($songID, $uploadedAudio); + } + + exit; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + exit; + } + } + + + public function search($params) + { + try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + $q = ''; + if (isset($params)) { + + $decodedString = str_replace('_', ' ', $params); + $q = $decodedString; + } + // var_dump($params); + $songModel = $this->model('SongModel'); + + $songArr = $songModel->getByQuery($q); + + // var_dump($songArr); + + header('Content-Type: application/json'); + // Encode the data as JSON and send it as the response. + echo json_encode($songArr); + exit; + + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } catch (Exception $e) { + http_response_code($e->getCode()); + } + } + +} diff --git a/src/app/controllers/UserController.php b/src/app/controllers/UserController.php new file mode 100644 index 0000000000000000000000000000000000000000..1ecc8d4cdb3ee402a6237eff2e43a1cd8a195271 --- /dev/null +++ b/src/app/controllers/UserController.php @@ -0,0 +1,36 @@ +<?php +class UserController extends Controller implements ControllerInterface +{ + public function index() + { + try { + switch($_SERVER['REQUEST_METHOD']) { + case 'GET': + $data = new stdClass(); + + $user_model = $this->model('UserModel'); + $user_data = $user_model->getUserFromId($_SESSION['user_id'] ?? 1); + $data->user_data= $user_data[0]; + + $song_model = $this->model('SongModel'); + $data->song_data = $song_model->getSongByUserId($_SESSION['user_id'] ?? 1); +// var_dump($data); + + $data->photo_profile = 'http://localhost:8080/storage/images/'. $data->photo_profile; +// + $homeView=$this->view('user','UserView', $data); + $homeView->render(); + break; + default: + throw new LoggedException('Method Not Allowed', 405); + } + } + catch (Exception $e) { + http_response_code($e->getCode()); + } + // Need to check first whether session exists, then proceed + //if not exists, redirect to login page + // $user_data = $this->model('UserModel')->getUserFromId($_SESSION['user_id']); + } +} +?> \ No newline at end of file diff --git a/src/app/core/App.php b/src/app/core/App.php new file mode 100644 index 0000000000000000000000000000000000000000..c00b0246cade5cd574ced49de667f6c2d0d2aa87 --- /dev/null +++ b/src/app/core/App.php @@ -0,0 +1,73 @@ +<?php + +// define("BASE_DIR", $_ENV['PWD'] . '/src/app/controllers/'); +// require_once BASE_URL . "/src/app/middlewares/Middleware.php"; + +class App { + protected $controller = 'HomeController'; + protected $method = 'index'; + public $params = []; + + public function __construct() { + require_once __DIR__ . '/../controllers/' . 'HomeController.php'; + $this->controller = new HomeController(); + $this->method = 'index'; + // Explode URL + // [0] : controller + // [1] : method/ params + // Example : podcast/1, podcast/add + + // Middleware::checkReferer(); + + $url = $this->parseURL(); + // var_dump(($url)); + $controllerPart = $url[0] ?? null; + if (isset($controllerPart) && file_exists(__DIR__ . '/../controllers/' . $url[0] . 'Controller.php')) { + require_once __DIR__ . '/../controllers/' . $url[0] . 'Controller.php'; + $controllerClass = $url[0].'Controller'; + $this->controller = new $controllerClass(); + // var_dump(($url)); + unset($url[0]); + } + // var_dump($controllerPart); + + // Cek bagian method: jika filenya ada, gunakan method tersebut; jika tidak, pakai yang default (index) + $methodPart = $url[1] ?? null; + if (isset($methodPart) && method_exists($this->controller, $methodPart)) { + $this->method = $methodPart; + unset($url[1]); + } + + // Cek bagian parameter + if (!empty($url)) { + // var_dump(($url)); + $this->params = array_values($url); + } else { + $this->params = []; + } + + + // Panggil method dari kelas controller, dengan parameter params + call_user_func_array([$this->controller, $this->method], $this->params); + + } + + /** + * URL Parser into an array of components. + * + * @return array An array containing URL components, or [] if 'url' is not set. + */ + public function parseURL() { + if (isset($_GET['url'])) { + $url = $_GET['url']; + $url = filter_var($url, FILTER_SANITIZE_URL); + $url = explode('/', $url); + + return $url; + } + + // var_dump($_GET['url']); + + // return []; + } +} diff --git a/src/app/core/Controller.php b/src/app/core/Controller.php new file mode 100644 index 0000000000000000000000000000000000000000..004e5ac1b603ad132ad85b3a0b902fc05ee9a875 --- /dev/null +++ b/src/app/core/Controller.php @@ -0,0 +1,17 @@ +<?php + +class Controller +{ + public function view($folder, $view, $data = []) + { + require_once __DIR__ . '/../views/' . $folder . '/' . $view . '.php'; + return new $view($data); + } + + public function model($model) + { + require_once __DIR__ . '/../models/' . $model . '.php'; + return new $model(); + } + +} diff --git a/src/app/core/Database.php b/src/app/core/Database.php new file mode 100644 index 0000000000000000000000000000000000000000..732008ff5f8290289b32e39cbf08afffd0fc53e1 --- /dev/null +++ b/src/app/core/Database.php @@ -0,0 +1,116 @@ +<?php + +class Database +{ + private $host = HOST; + private $db_name = DBNAME; + private $user = USER; + private $password = PASSWORD; + private $port = PORT; + + private $db_connection; + private $statement; + + public function __construct() + { + // phpinfo(); + $dsn = 'pgsql:host=' . $this->host . ';port=' . $this->port . ';dbname=' . $this->db_name; + $option = [ + PDO::ATTR_PERSISTENT => true, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION + ]; + + try { + $this->db_connection = new PDO($dsn, $this->user, $this->password, $option); + } catch (PDOException $e) { + // echo "PDO Exception: " . $e->getMessage(); + // echo "Error Code: " . $e->getCode(); + throw new LoggedException('Bad Gateway', 502); + } + + try { + // $this->db_connection->exec(Tables::USER_TABLE); + // $this->db_connection->exec(Tables::PLAYLIST_TABLE); + // $this->db_connection->exec(Tables::SONG_TABLE); + + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function query($query) + { + try { + $this->statement = $this->db_connection->prepare($query); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function bind($param, $value, $type = null) + { + try { + if (is_null($type)) { + if (is_int($value)) { + $type = PDO::PARAM_INT; + } else if (is_bool($value)) { + $type = PDO::PARAM_BOOL; + } else if (is_null($value)) { + $type = PDO::PARAM_NULL; + } else { + $type = PDO::PARAM_STR; + } + } + $this->statement->bindValue($param, $value, $type); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function execute() + { + try { + $this->statement->execute(); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function fetch() + { + try { + $this->execute(); + return $this->statement->fetch(PDO::FETCH_OBJ); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function fetchAll() + { + try { + $this->execute(); + return $this->statement->fetchAll(PDO::FETCH_OBJ); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function rowCount() + { + try { + return $this->statement->rowCount(); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } + + public function lastInsertID() + { + try { + return $this->db_connection->lastInsertId(); + } catch (PDOException) { + throw new LoggedException('Internal Server Error', 500); + } + } +} diff --git a/src/app/core/StorageAccess.php b/src/app/core/StorageAccess.php new file mode 100644 index 0000000000000000000000000000000000000000..415975bf2788f8c7f2550c7151e0219c5a592ff0 --- /dev/null +++ b/src/app/core/StorageAccess.php @@ -0,0 +1,83 @@ +<?php + +class StorageAccess +{ + private $storageDir; + + public const IMAGE_PATH = 'images'; + public const SONG_PATH = 'songs'; + + public function __construct($foldername) + { + $this->storageDir = __DIR__ . '/../../storage/' . $foldername . '/'; + } + + private function doesFileExist($filename) + { + return file_exists($this->storageDir . $filename); + } + + public function saveAudio($tempname) + { + $filesize = filesize($tempname); + if ($filesize > MAX_SIZE) { + throw new LoggedException('Request Entity Too Large', 413); + } + + $mimetype = mime_content_type($tempname); + if (!in_array($mimetype, array_keys(ALLOWED_AUDIOS))) { + throw new LoggedException('Unsupported Media Type', 415); + } + + $valid = false; + while (!$valid) { + $filename = md5(uniqid(mt_rand(), true)) . ALLOWED_AUDIOS[$mimetype]; + $valid = !$this->doesFileExist($filename); + } + + $success = move_uploaded_file($tempname, $this->storageDir . $filename); + if (!$success) { + throw new LoggedException('Internal Server Error', 500); + } + + return $filename; + } + + public function saveImage($tempname) + { + $filesize = filesize($tempname); + if ($filesize > MAX_SIZE) { + throw new LoggedException('Request Entity Too Large', 413); + } + + $mimetype = mime_content_type($tempname); + if (!in_array($mimetype, array_keys(ALLOWED_IMAGES))) { + throw new LoggedException('Unsupported Media Type', 415); + } + + $valid = false; + while (!$valid) { + $filename = md5(uniqid(mt_rand(), true)) . ALLOWED_IMAGES[$mimetype]; + $valid = !$this->doesFileExist($filename); + } + + $success = move_uploaded_file($tempname, $this->storageDir . $filename); + if (!$success) { + throw new LoggedException('Internal Server Error', 500); + } + + return $filename; + } + + public function deleteFile($filename) + { + if (!$this->doesFileExist($filename)) { + return; + } + + $success = unlink($this->storageDir . $filename); + if (!$success) { + throw new LoggedException('Internal Server Error', 500); + } + } +} diff --git a/src/app/exceptions/LoggedException.php b/src/app/exceptions/LoggedException.php new file mode 100644 index 0000000000000000000000000000000000000000..39787935c54ca5343dc3b6019afcb20305ca1b84 --- /dev/null +++ b/src/app/exceptions/LoggedException.php @@ -0,0 +1,15 @@ +<?php + +class LoggedException extends Exception +{ + public function __construct($message = '', $code = 0) + { + parent::__construct($message, $code); + $this->logError($message, $code); + } + + private function logError($message, $code) + { + error_log('[ERROR] ' . $code . ': ' . $message); + } +} diff --git a/src/app/init.php b/src/app/init.php new file mode 100644 index 0000000000000000000000000000000000000000..20f7c0511b04ef7473eeffe06a9a3cfbd3fcf923 --- /dev/null +++ b/src/app/init.php @@ -0,0 +1,12 @@ +<?php + +require_once 'core/App.php'; +require_once 'core/Controller.php'; +require_once 'config/config.php'; +require_once 'core/StorageAccess.php'; +require_once 'exceptions/LoggedException.php'; +require_once 'interfaces/ControllerInterface.php'; +require_once 'interfaces/ViewInterface.php'; + +require_once 'core/Database.php'; + diff --git a/src/app/interfaces/ControllerInterface.php b/src/app/interfaces/ControllerInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..be86b57c61c8ff8b3210a1c2efb2f14580be701f --- /dev/null +++ b/src/app/interfaces/ControllerInterface.php @@ -0,0 +1,6 @@ +<?php + +interface ControllerInterface +{ + public function index(); +} diff --git a/src/app/interfaces/ViewInterface.php b/src/app/interfaces/ViewInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..9f77634b7f841e596227e5e08125c550970f3fc4 --- /dev/null +++ b/src/app/interfaces/ViewInterface.php @@ -0,0 +1,6 @@ +<?php + +interface ViewInterface +{ + public function render(); +} diff --git a/src/app/models/AdminModel.php b/src/app/models/AdminModel.php new file mode 100644 index 0000000000000000000000000000000000000000..b35ff94fad08df870e3fa6d3fbb87c0ce137475a --- /dev/null +++ b/src/app/models/AdminModel.php @@ -0,0 +1,18 @@ +<?php + +class AdminModel +{ + private $database; + + public function __construct() + { + $this->database = new Database(); + } + + public function getAllUsers() + { + $query = 'SELECT user_id, email, username, fullname FROM "user" '; + $this->database->query($query); + return $this->database->fetchAll(); + } +} diff --git a/src/app/models/AlbumModel.php b/src/app/models/AlbumModel.php new file mode 100644 index 0000000000000000000000000000000000000000..c2419aa95783011a290d803413e3c9e065697555 --- /dev/null +++ b/src/app/models/AlbumModel.php @@ -0,0 +1,79 @@ +<?php + +class AlbumModel +{ + private $database; + + public function __construct() + { + $this->database = new Database(); + } + + public function getAllAlbum() + { + $query = 'SELECT DISTINCT * FROM Album'; + $this->database->query($query); + $albumArr = $this->database->fetchAll(); + + return $albumArr; + } + + public function getAlbumFromID($albumID) + { + $query = 'SELECT album_id, judul, penyanyi, year, image FROM album WHERE album_id = :album_id LIMIT 1'; + + $this->database->query($query); + $this->database->bind('album_id', $albumID); + + $album = $this->database->fetch(); + + return $album; + } + + public function addAlbum($judul, $penyanyi, $year, $image) + { + $query = 'INSERT INTO album (judul, penyanyi, year, image ) VALUES (:judul, :penyanyi, :year, :image)'; + + $this->database->query($query); + $this->database->bind('judul', $judul); + $this->database->bind('penyanyi', $penyanyi); + $this->database->bind('year', $year); + $this->database->bind('image', $image); + + $this->database->execute(); + + return ; + } + + public function deleteAlbum($albumID) + { + $query = 'DELETE FROM album WHERE album_id = :album_id'; + + $this->database->query($query); + $this->database->bind('album_id', $albumID); + $this->database->execute(); + } + + public function changeAlbumJudul($albumID, $newTitle) + { + $query = 'UPDATE album SET judul = :judul WHERE album_id = :album_id'; + + $this->database->query($query); + $this->database->bind('judul', $newTitle); + $this->database->bind('album_id', $albumID); + $this->database->execute(); + } + + public function changeAlbumImage($albumID, $newPath) + { + $query = 'UPDATE album SET image = :image WHERE album_id = :album_id'; + + $this->database->query($query); + $this->database->bind('image', $newPath); + $this->database->bind('album_id', $albumID); + $this->database->execute(); + } + + + +} diff --git a/src/app/models/AuthModel.php b/src/app/models/AuthModel.php new file mode 100644 index 0000000000000000000000000000000000000000..1fc00e7ea6859a902b9e1e0ae550ff86b6054507 --- /dev/null +++ b/src/app/models/AuthModel.php @@ -0,0 +1,116 @@ +<?php + +class AuthModel{ + private $database; + + public function __construct() { + $this->database = new Database(); + } + + public function signin($email, $password){ + $query = 'SELECT user_id, password FROM "user" WHERE email = :email LIMIT 1'; + + $this->database->query($query); + $this->database->bind('email', $email); + + $user = $this->database->fetch(); + + if ($user && password_verify($password, $user->password)) { + return $user->user_id; + } else { + throw new LoggedException('Unauthorized', 401); + } + } + + public function signup($email, $username, $fullname, $password, $is_admin){ + $query = 'INSERT INTO "user" (email, username, fullname, password, is_admin) VALUES (:email, :username, :fullname, :pass, :is_admin)'; + $options = [ + 'cost' => BCRYPT_COST + ]; + + $this->database->query($query); + $this->database->bind('email', $email); + $this->database->bind('username', $username); + $this->database->bind('fullname', $fullname); + $this->database->bind('pass', password_hash($password, PASSWORD_BCRYPT, $options)); + $this->database->bind('is_admin', false); + + $this->database->execute(); + } + + public function isEmailExist($email){ + $query = 'SELECT email FROM "user" WHERE email = :email LIMIT 1'; + + $this->database->query($query); + $this->database->bind('email', $email); + + $user = $this->database->fetch(); + + return $user; + } + + public function isUsernameExist($username) + { + $query = 'SELECT username FROM "user" WHERE username = :username LIMIT 1'; + + $this->database->query($query); + $this->database->bind('username', $username); + + $user = $this->database->fetch(); + + return $user; + } + + // public function getUSerFromID($user_ID){ + // $query = 'SELECT username, is_admin FROM user WHERE user_id = :user_id LIMIT 1'; + // $this->database->query($query); + // $this->database->bind('user_id',$user_ID); + + // $user = $this->database->fetch(); + + // return $user; + // } + + // public function getUsers($page){ + // $query='SELECT fullname, email, username, is_admin FROM user LIMIT :limit OFFSET :offset'; + + // $this->database->query($query); + // $this->database->bind('limit', ROWS_PER_PAGE); + // $this->database->bind('offset', ($page - 1) * ROWS_PER_PAGE); + // $users = $this->database->fetchAll(); + + // $query = 'SELECT CEIL(COUNT(user_id) / :rows_per_page) AS page_count FROM user'; + + // $this->database->query($query); + // $this->database->bind('rows_per_page', ROWS_PER_PAGE); + // $user = $this->database->fetch(); + // $pageCount = $user->page_count; + + // $returnArr = ['users' => $users, 'pages' => $pageCount]; + // return $returnArr; + + // } + + + + // public function register($email, $username, $password, $fullname) + // { + // $query = 'INSERT INTO user (email, username, fullname, password, is_admin) VALUES (:email, :username, :fullname, :password, :is_admin)'; + // $options = [ + // 'cost' => BCRYPT_COST + // ]; + + // $this->database->query($query); + // $this->database->bind('email', $email); + // $this->database->bind('username', $username); + // $this->database->bind('fullname', $fullname); + // $this->database->bind('password', password_hash($password, PASSWORD_BCRYPT, $options)); + // $this->database->bind('is_admin', false); + + // $this->database->execute(); + // } + + + + +} \ No newline at end of file diff --git a/src/app/models/SongModel.php b/src/app/models/SongModel.php new file mode 100644 index 0000000000000000000000000000000000000000..71c25c6cbec587d62278cecd735b5cdf6fb4003c --- /dev/null +++ b/src/app/models/SongModel.php @@ -0,0 +1,135 @@ +<?php + +class SongModel +{ + private $database; + + public function __construct() { + $this->database=new Database(); + } + + public function getAllsongs(){ + $query = 'SELECT * FROM (SELECT * FROM song ORDER BY song_id DESC);'; + $this->database->query($query); + $jsonData = $this->database->fetchAll(); + return $jsonData; + } + + public function getByQuery($q, $sort = 'judul', $filter ='all', $page = 1) + { + if ($filter === 'all') { + $query = 'SELECT * FROM song WHERE (judul LIKE :q or penyanyi LIKE :q) ORDER BY song_id DESC LIMIT :limit;'; + } + else { + $query = 'SELECT * FROM song WHERE (judul LIKE :q or penyanyi like :q) ORDER BY song_id DESC LIMIT :limit;'; + } + $this->database->query($query); + $this->database->bind('limit', 100); + // $this->database->bind('offset', ($page - 1) * ROWS_PER_PAGE); + $this->database->bind('q', '%' . $q . '%'); + // $this->database->bind('sort', $sort); + // if ($filter !== 'all') { + // $this->database->bind('filter', $filter); + // } + $this->database->execute(); + $songArr = $this->database->fetchAll(); + // $pages_count = $this->getPagesCount($q, $filter); + // $return_array = ["songs" => $songArr, "pages" => $pages_count]; + $return_array = $songArr; + + + return $return_array; + } + public function getSongByUserId($userId){ + $query = 'SELECT * FROM song WHERE song_id = :user_id LIMIT 1'; + $this->database->query($query); + $this->database->bind(':user_id', $userId); + $song = $this->database->fetchAll(); + return $song; + } + + public function addSong($judul, $penyanyi, $year, $audio, $image, $album_id) { + if ($album_id == "undef") { + $query = "INSERT INTO song (judul, penyanyi, year, audio, image) + VALUES (:judul, :penyanyi, :year, :audio, :image)"; + } else { + $query = "INSERT INTO song (judul, penyanyi, year, audio, image, album_id) + VALUES (:judul, :penyanyi, :year, :audio, :image, :album_id)"; + } + $this->database->query($query); + $this->database->bind('judul', $judul); + $this->database->bind('penyanyi', $penyanyi); + $this->database->bind('year', $year); + $this->database->bind('audio', $audio); + $this->database->bind('image', $image); + // $this->database->bind('', $genre); + // $this->database->bind('duration', $duration); + if ($album_id != "undef") { + $this->database->bind('album_id', (int) $album_id); + } + $this->database->execute(); + + return $this->database->lastInsertID(); + } + + public function getPagesCount($q, $filter = 'all') + { + if ($filter === 'all') { + $query = "SELECT COUNT(*) count_result FROM song WHERE (judul LIKE :q or penyanyi LIKE :q or tanggal_terbit LIKE :q)"; + } + else { + $query = "SELECT COUNT(*) count_result FROM song WHERE (judul LIKE :q or penyanyi like :q or tanggal_terbit like :q) and genre = :filter"; + } + $this->database->query($query); + $this->database->bind('q', '%' . $q . '%'); + if ($filter !== 'all') { + $this->database->bind('filter', $filter); + } + $count = $this->database->fetch(); + $pages_count = ceil($count->count_result / ROWS_PER_PAGE); + return $pages_count; + } + + public function deleteSong($songID) { + $query = 'DELETE FROM song WHERE song_id = :song_id'; + + $this->database->query($query); + $this->database->bind('song_id', $songID); + $this->database->execute(); + } + + public function getAlbumFromSongID($songID){ + $query = 'SELECT *,album.judul as judul_album FROM song INNER JOIN album ON song.album_id=album.album_id WHERE song.song_id=:song_id;'; + $this->database->query($query); + $this->database->bind('song_id',$songID); + $album=$this->database->fetch(); + return $album; + } + + public function changeSongTitle($songID, $newTitle) { + $query = 'UPDATE song SET judul = :judul WHERE song_id = :song_id'; + + $this->database->query($query); + $this->database->bind('judul', $newTitle); + $this->database->bind('song_id', $songID); + $this->database->execute(); + } + + public function changeImagePath($songID, $newPath) { + $query = 'UPDATE song SET image = :image WHERE song_id = :song_id;'; + + $this->database->query($query); + $this->database->bind('image', $newPath); + $this->database->bind('song_id', $songID); + $this->database->execute(); + } + + public function changeAudioPath($songID, $newPath) { + $query = 'UPDATE song SET audio = :audio WHERE song_id = :song_id;'; + + $this->database->query($query); + $this->database->bind('audio', $newPath); + $this->database->bind('song_id', $songID); + $this->database->execute(); + } +} diff --git a/src/app/models/UserModel.php b/src/app/models/UserModel.php new file mode 100644 index 0000000000000000000000000000000000000000..d22016942ef1fbd9e940c3342b86d8ae902d68ea --- /dev/null +++ b/src/app/models/UserModel.php @@ -0,0 +1,103 @@ +<?php + +class UserModel{ + private $database; + + public function __construct() { + $this->database = new Database(); + } + + public function getAll(){ + $query = 'SELECT * FROM "user"'; + $this->database->query($query); + + return $this->database->fetchAll(); + } + + public function getUserFromId($user_ID){ + $query = 'SELECT fullname, username, email, is_admin, photo_profile FROM "user" WHERE user_id = :user_id LIMIT 1'; + $this->database->query($query); + $this->database->bind('user_id',$user_ID); + + $user = $this->database->fetchAll(); + + return $user; + } + + public function getUsers($page){ + $query='SELECT fullname, email, username, is_admin FROM user LIMIT :limit OFFSET :offset'; + + $this->database->query($query); + $this->database->bind('limit', ROWS_PER_PAGE); + $this->database->bind('offset', ($page - 1) * ROWS_PER_PAGE); + $users = $this->database->fetchAll(); + + $query = 'SELECT CEIL(COUNT(user_id) / :rows_per_page) AS page_count FROM user'; + + $this->database->query($query); + $this->database->bind('rows_per_page', ROWS_PER_PAGE); + $user = $this->database->fetch(); + $pageCount = $user->page_count; + + $returnArr = ['users' => $users, 'pages' => $pageCount]; + return $returnArr; + + } + + public function login($username, $password) + { + $query = 'SELECT user_id, password FROM user WHERE username = :username LIMIT 1'; + + $this->database->query($query); + $this->database->bind('username', $username); + + $user = $this->database->fetch(); + + if ($user && password_verify($password, $user->password)) { + return $user->user_id; + } else { + throw new LoggedException('Unauthorized', 401); + } + } + + public function register($email, $username, $password, $fullname) + { + $query = 'INSERT INTO user (email, username, fullname, password, is_admin) VALUES (:email, :username, :fullname, :password, :is_admin)'; + $options = [ + 'cost' => BCRYPT_COST + ]; + + $this->database->query($query); + $this->database->bind('email', $email); + $this->database->bind('username', $username); + $this->database->bind('fullname', $fullname); + $this->database->bind('password', password_hash($password, PASSWORD_BCRYPT, $options)); + $this->database->bind('is_admin', false); + + $this->database->execute(); + } + + public function doesEmailExist($email) + { + $query = 'SELECT email FROM user WHERE email = :email LIMIT 1'; + + $this->database->query($query); + $this->database->bind('email', $email); + + $user = $this->database->fetch(); + + return $user; + } + + public function doesUsernameExist($username) + { + $query = 'SELECT username FROM user WHERE username = :username LIMIT 1'; + + $this->database->query($query); + $this->database->bind('username', $username); + + $user = $this->database->fetch(); + + return $user; + } +} \ No newline at end of file diff --git a/src/app/views/album/AddAlbumView.php b/src/app/views/album/AddAlbumView.php new file mode 100644 index 0000000000000000000000000000000000000000..fd20b06ee9bfe14c4690e2d3628ceb5f619c14bb --- /dev/null +++ b/src/app/views/album/AddAlbumView.php @@ -0,0 +1,13 @@ +<?php + +class AddAlbumView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/album/AddAlbum.php'; + } +} \ No newline at end of file diff --git a/src/app/views/album/AlbumView.php b/src/app/views/album/AlbumView.php new file mode 100644 index 0000000000000000000000000000000000000000..e1a894d6a399605c220e2ef82306d42dcd00219d --- /dev/null +++ b/src/app/views/album/AlbumView.php @@ -0,0 +1,13 @@ +<?php + +class AlbumView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/album/AlbumPage.php'; + } +} \ No newline at end of file diff --git a/src/app/views/album/EditAlbumView.php b/src/app/views/album/EditAlbumView.php new file mode 100644 index 0000000000000000000000000000000000000000..6ac55402113be1078aaf0c8069f1fce12339a5b9 --- /dev/null +++ b/src/app/views/album/EditAlbumView.php @@ -0,0 +1,13 @@ +<?php + +class EditAlbumView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/album/EditAlbum.php'; + } +} \ No newline at end of file diff --git a/src/app/views/auth/SignInView.php b/src/app/views/auth/SignInView.php new file mode 100644 index 0000000000000000000000000000000000000000..0143327deac0441335578b6289e9e0f8a74d8c8d --- /dev/null +++ b/src/app/views/auth/SignInView.php @@ -0,0 +1,14 @@ +<?php + +class SignInView implements ViewInterface +{ + public $data; + public function __construct($data = []){ + $this->data = $data; + } + + public function render(){ + require_once __DIR__ . '/../../components/auth/SignIn.php'; + } + +} diff --git a/src/app/views/auth/SignUpView.php b/src/app/views/auth/SignUpView.php new file mode 100644 index 0000000000000000000000000000000000000000..c48190c218798f4e09ab49baf17801400daa7917 --- /dev/null +++ b/src/app/views/auth/SignUpView.php @@ -0,0 +1,14 @@ +<?php + +class SignUpView implements ViewInterface +{ + public $data; + public function __construct($data = []){ + $this->data = $data; + } + + public function render(){ + require_once __DIR__ . '/../../components/auth/SignUp.php'; + } + +} diff --git a/src/app/views/home/MainView.php b/src/app/views/home/MainView.php new file mode 100644 index 0000000000000000000000000000000000000000..fb3c3f56428013096bda0dc79761fe5f78e4583e --- /dev/null +++ b/src/app/views/home/MainView.php @@ -0,0 +1,13 @@ +<?php + +class MainView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/home/HomePage.php'; + } +} \ No newline at end of file diff --git a/src/app/views/not-found/NotFoundView.php b/src/app/views/not-found/NotFoundView.php new file mode 100644 index 0000000000000000000000000000000000000000..48539df8f2e4893ae75cec27e57a24d3cc80fb04 --- /dev/null +++ b/src/app/views/not-found/NotFoundView.php @@ -0,0 +1,14 @@ +<?php + +class NotFoundView implements ViewInterface +{ + public function __construct($data = []) + { + $this->data = $data; + } + + public function render() + { + require_once __DIR__ . '/../../components/not-found/NotFoundPage.php'; + } +} diff --git a/src/app/views/song/AddSongView.php b/src/app/views/song/AddSongView.php new file mode 100644 index 0000000000000000000000000000000000000000..271404856e67cca8f42f839341e4b09b9a37a0c9 --- /dev/null +++ b/src/app/views/song/AddSongView.php @@ -0,0 +1,13 @@ +<?php + +class AddSongView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/song/AddSong.php'; + } +} \ No newline at end of file diff --git a/src/app/views/song/EditSongView.php b/src/app/views/song/EditSongView.php new file mode 100644 index 0000000000000000000000000000000000000000..0914e5da9628ec9521c994ebdf7a7f79f323227e --- /dev/null +++ b/src/app/views/song/EditSongView.php @@ -0,0 +1,13 @@ +<?php + +class EditSongView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/song/EditSong.php'; + } +} \ No newline at end of file diff --git a/src/app/views/user/AdminView.php b/src/app/views/user/AdminView.php new file mode 100644 index 0000000000000000000000000000000000000000..d7558eb09cf8194e2748506f472ede62dab1287e --- /dev/null +++ b/src/app/views/user/AdminView.php @@ -0,0 +1,15 @@ +<?php + +class AdminView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/user/AdminPage.php'; + } +} + +?> \ No newline at end of file diff --git a/src/app/views/user/UserView.php b/src/app/views/user/UserView.php new file mode 100644 index 0000000000000000000000000000000000000000..7e64837a5987d916a2a818df43883aeb42980361 --- /dev/null +++ b/src/app/views/user/UserView.php @@ -0,0 +1,15 @@ +<?php + +class UserView implements ViewInterface +{ + public $data; + public function __construct($data = []) { + $this->data = $data; + } + + public function render() { + require_once __DIR__ . '/../../components/user/UserPage.php'; + } +} + +?> \ No newline at end of file diff --git a/src/public/.htaccess b/src/public/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..24b76fb6d90c49de8fdc87a651f2632e450bf8ea --- /dev/null +++ b/src/public/.htaccess @@ -0,0 +1,9 @@ +Options -Multiviews -Indexes + +RewriteEngine On +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^(.*)$ index.php?url=$1 [L] + +php_value upload_max_filesize 40M +php_value post_max_size 40M \ No newline at end of file diff --git a/src/public/Controller/album.js b/src/public/Controller/album.js new file mode 100644 index 0000000000000000000000000000000000000000..b83e7933d722609f34191dc4a4e4a00ffa621742 --- /dev/null +++ b/src/public/Controller/album.js @@ -0,0 +1,107 @@ +// Add an event listener to the "Upload" button +if(document.getElementById('submitFormAlbum')!=null){ + + document.getElementById('submitFormAlbum').addEventListener('click', async function() { + // Get the form element + var form = document.getElementById('fileUploadForm'); + + // Create a FormData object to gather the form data + var formData = new FormData(form); + + // Log the form data to the console + // console.log("Form Data:"); + for (var pair of formData.entries()) { + console.log(pair[0] + ': ' + pair[1]); + } + + // Send the form data to the backend PHP script using AJAX + var xhr = new XMLHttpRequest(); + await xhr.open('POST', '/public/album/add', true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + // xhr.setRequestHeader("Content-Type", "multipart/form-data"); + + // Set up a callback function to handle the response from the server + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + // Handle the response from the server if needed + console.log(xhr.responseText); + window.location.href = "/public/album/index"; + } + }; + xhr.send(formData); + // Send the FormData object to the server + }); +} + +async function deleteAlbum(idx){ + + console.log(dataDummyAlbum[idx]); + const formData = new FormData(); + for (const key in dataDummyAlbum[idx]) { + if (dataDummyAlbum[idx].hasOwnProperty(key)) { + formData.append(key, dataDummyAlbum[idx][key]); + } + } + + // for (const pair of formData.entries()) { + // console.log(pair[0] + ': ' + pair[1]); + // } + + // console.log(formData); + var resultAlbum = confirm("All song in this album will be deleted!"); + + // Check the user's choice + if (resultAlbum === true) { + // The user clicked "OK," so proceed with the deletion + var xhr = new XMLHttpRequest(); + await xhr.open('POST', '/public/Album/delete', true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // Set up a callback function to handle the response from the server + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + // Handle the response from the server if needed + console.log(xhr.responseText); + window.location.href = "/public/album"; + } + }; + xhr.send(formData); + } else { + // The user clicked "Cancel," so do nothing + // alert("Deletion canceled!"); + } +} + +// Add an event listener to the "Upload" button +if(document.getElementById('submitFormEdit')!==null){ + + document.getElementById('submitFormEdit').addEventListener('click', function() { + // Get the form element + var form = document.getElementById('fileUploadFormEdit'); + + // Create a FormData object to gather the form data + var formData = new FormData(form); + var url = new URL(window.location.href); + console.log(url.pathname); + // Log the form data to the console + // console.log("Form Data:"); + for (var pair of formData.entries()) { + console.log(pair[0] + ': ' + pair[1]); + } + // Send the form data to the backend PHP script using AJAX + var xhr = new XMLHttpRequest(); + xhr.open('POST', url.pathname, true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + // xhr.setRequestHeader("Content-Type", "multipart/form-data"); + + // Set up a callback function to handle the response from the server + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + // Handle the response from the server if needed + console.log(xhr.responseText); + window.location.href = "/public/album/index"; + } + }; + xhr.send(formData); + }); +} \ No newline at end of file diff --git a/src/public/Controller/controller.js b/src/public/Controller/controller.js new file mode 100644 index 0000000000000000000000000000000000000000..6475d242e22dca758fdace92ec13cacaba8f2805 --- /dev/null +++ b/src/public/Controller/controller.js @@ -0,0 +1,38 @@ +var isPlayed=false; +var isPause=true; +var lastActivateID=null; + +function playStopClick(id){ + console.log(id); + if(id==lastActivateID){ + if(!isPlayed){ + loadTrack(id); + } + if(!isPlaying){ + document.getElementById(id).classList.add("pause"); + isPlayed=true; + lastActivateID=id; + playTrack(id); + // isPlaying=true; + console.log('a') + }else{ + document.getElementById(id).classList.remove("pause"); + pauseTrack(); + // isPlaying=false; + console.log('b') + } + }else{ + loadTrack(id); + if(isPlayed){ + document.getElementById(lastActivateID).classList.remove("pause"); + lastActivateID=id; + } + console.log(document.getElementById(id)); + document.getElementById(id).classList.add("pause"); + lastActivateID=id; + isPlayed=true; + pauseTrack() + playTrack(id); + console.log('c') + } +} diff --git a/src/public/Controller/controllerPlayer.js b/src/public/Controller/controllerPlayer.js new file mode 100644 index 0000000000000000000000000000000000000000..03b18b8e3d307917c82c64713be1de61d99ec61b --- /dev/null +++ b/src/public/Controller/controllerPlayer.js @@ -0,0 +1,180 @@ + +var isPlaying=false; +var isPlayed=false; + +let track_index = 0; +let updateTimer; + +// Create the audio element for the player +let curr_track = document.createElement('audio'); +// Select all the elements in the HTML page +// and assign them to a variable +let now_playing = document.querySelector(".now-playing"); +let track_art = document.querySelector(".track-art"); +let track_name = document.querySelector(".track-name"); +let track_artist = document.querySelector(".track-artist"); + +let playpause_btn = document.querySelector(".playpause-track"); +let next_btn = document.querySelector(".next-track"); +let prev_btn = document.querySelector(".prev-track"); + +let seek_slider = document.querySelector(".seek_slider"); +let volume_slider = document.querySelector(".volume_slider"); +let curr_time = document.querySelector(".current-time"); +let total_duration = document.querySelector(".total-duration"); + + +function playpauseTrack() { + // Switch between playing and pausing + // depending on the current state + // console.log("dawawdawd"); + if(isPlayed){ + if (!isPlaying) playTrack(); + else pauseTrack(); + }else{ + + } +} + +function playTrack(id=lastActivateID) { + // Play the loaded track + console.log(id); + curr_track.play(); + // document.getElementById(lastActivateID).classList.add("pause") + isPlaying = true; + document.getElementById(lastActivateID).classList.add('pause') + // if(isPlayed){ + // document.querySelector(".searchText").textContent=`Now Playing : ${dataDummy[lastActiveID].title}` + // } + document.querySelector(".searchText").textContent=`Now Playing : ${dataDummy[id].judul}` + // Replace icon with the pause icon + playpause_btn.innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>'; + +} + +function pauseTrack() { + // Pause the loaded track + curr_track.pause(); + + isPlaying = false; + document.getElementById(lastActivateID).classList.remove('pause') + document.querySelector(".searchText").textContent=`Now Playing : ` + // Replace icon with the play icon + playpause_btn.innerHTML = '<i class="fa fa-play-circle fa-5x"></i>'; +} + +function nextTrack() { + // Go back to the first track if the + // current one is the last in the track list + // if (track_index < track_list.length - 1) + // track_index += 1; + // else track_index = 0; + + // Load and play the new track + if(isPlayed){ + + if(lastActivateID<dataDummy.length-1){ + playStopClick(lastActivateID+1) + }else{ + playStopClick(0); + // loadTrack(0); + // playTrack(0); + } + } +} + +function prevTrack() { + // Go back to the last track if the + // current one is the first in the track list + // if (track_index > 0) + // track_index -= 1; + // else track_index = track_list.length - 1; + + // Load and play the new track + if(isPlayed){ + + if(lastActivateID>0){ + playStopClick(lastActivateID-1) + }else{ + // playStopClick(0); + loadTrack(0); + playTrack(0); + } + } +} + +function seekTo() { + // Calculate the seek position by the + // percentage of the seek slider + // and get the relative duration to the track + if(isPlayed){ + seekto = curr_track.duration * (seek_slider.value / 100); + + // Set the current track position to the calculated seek position + curr_track.currentTime = seekto; + } +} + +function seekUpdate() { + let seekPosition = 0; + + // Check if the current track duration is a legible number + if (!isNaN(curr_track.duration)) { + seekPosition = curr_track.currentTime * (100 / curr_track.duration); + seek_slider.value = seekPosition; + + // Calculate the time left and the total duration + let currentMinutes = Math.floor(curr_track.currentTime / 60); + let currentSeconds = Math.floor(curr_track.currentTime - currentMinutes * 60); + let durationMinutes = Math.floor(curr_track.duration / 60); + let durationSeconds = Math.floor(curr_track.duration - durationMinutes * 60); + + // Add a zero to the single digit time values + if (currentSeconds < 10) { currentSeconds = "0" + currentSeconds; } + if (durationSeconds < 10) { durationSeconds = "0" + durationSeconds; } + if (currentMinutes < 10) { currentMinutes = "0" + currentMinutes; } + if (durationMinutes < 10) { durationMinutes = "0" + durationMinutes; } + + // Display the updated duration + curr_time.textContent = currentMinutes + ":" + currentSeconds; + total_duration.textContent = durationMinutes + ":" + durationSeconds; + } +} + +function loadTrack(track_index) { + // Clear the previous seek timer + clearInterval(updateTimer); + resetValues(); + + // console.log(dataDummy); + // // Load a new track + // console.log(location.href); + console.log(dataDummy[track_index].audio); + curr_track.src = 'http://localhost:8080/storage/songs/'+dataDummy[track_index].audio; + curr_track.load(); + + // Update details of the track + // track_art.style.backgroundImage = + // "url(" + track_list[track_index].image + ")"; + // track_name.textContent = track_list[track_index].name; + // track_artist.textContent = track_list[track_index].artist; + // now_playing.textContent = + // "PLAYING " + (track_index + 1) + " OF " + track_list.length; + + // Set an interval of 1000 milliseconds + // for updating the seek slider + updateTimer = setInterval(seekUpdate, 1000); + + // Move to the next track if the current finishes playing + // using the 'ended' event + curr_track.addEventListener("ended", nextTrack); + + // Apply a random background color + // random_bg_color(); +} + +function resetValues() { + curr_time.textContent = "00:00"; + total_duration.textContent = "00:00"; + seek_slider.value = 0; +} \ No newline at end of file diff --git a/src/public/Controller/dataController.js b/src/public/Controller/dataController.js new file mode 100644 index 0000000000000000000000000000000000000000..3d29a041497eb8c34c7faaa5e1e5810c6c761dfc --- /dev/null +++ b/src/public/Controller/dataController.js @@ -0,0 +1,6 @@ +// import data from '../Resources/Data/dummy.json' assert { type: 'json' }; + +// var dataDummy=[{}]; + +// dataDummy=data; +// console.log(dataDummy); diff --git a/src/public/Controller/debounce.js b/src/public/Controller/debounce.js new file mode 100644 index 0000000000000000000000000000000000000000..83ea92f41a06a393e799a6c796fa75e1153b1d35 --- /dev/null +++ b/src/public/Controller/debounce.js @@ -0,0 +1,9 @@ +let timer; +const debounce = (func, timeout) => { + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { + func.apply(this, args); + }, timeout); + }; +}; diff --git a/src/public/Controller/filterController.js b/src/public/Controller/filterController.js new file mode 100644 index 0000000000000000000000000000000000000000..15f6c3fd82f77d0a777ba1ae6970c853a788a2ec --- /dev/null +++ b/src/public/Controller/filterController.js @@ -0,0 +1,30 @@ + +// Assigning references to the filter buttons +// var filterButton = document.querySelectorAll('#filter'); +var removeFiltersButton = document.getElementById("removeFilters"); + +// When the filter button is clicked. The list is filtered by calling the filter function of the list object and passing in a function that accepts the list items. +function handleClickFilter(key){ + // key=filterButton.innerText; + switch (key) { + case 'Title': + console.log(key); + // dataDummy.sort((a, b) => a.title.localeCompare(b.title)).sort((a, b) => a.title.localeCompare(b.title)) + // console.log('yyyy') + break; + case 'Year': + console.log(key); + break; + case 'Author': + console.log(key); + break; + + default: + break; + } +} + +// When the remove filter button is clicked, the filters are removed by calling the filter function once again with no parameters. +// removeFiltersButton.addEventListener("click", function() { +// hackerList.filter(); +// }); \ No newline at end of file diff --git a/src/public/Controller/pagination.js b/src/public/Controller/pagination.js new file mode 100644 index 0000000000000000000000000000000000000000..337bb0028bf25b5583463e44dcff3a792d5d9908 --- /dev/null +++ b/src/public/Controller/pagination.js @@ -0,0 +1,53 @@ +var bar = document.getElementById('scroll'); +var item = document.getElementById('pagination'); + // window.addEventListener("wheel", function (e) { + // if (e.deltaY > 0) item.scrollLeft += 100; + // else item.scrollLeft -= 100; + // }); + + /** + * + * @param {int} itemsMatched : Number of items matched from query + * @param {int} itemsPerPage : Number of items per page + * @param {int} currPage : Current page on. !Warning, it will do funny consequence that usually occurs in mangadex + */ +function generatePagination(itemsMatched,itemsPerPage,currPage){// ini lemah sama cross site scripting + const maxPage = 5; //odd please + numPages = Math.ceil(itemsMatched/ itemsPerPage); + let start = -1; + if(currPage<maxPage){ + start = 1; + }else if(currPage>= (numPages-Math.floor(maxPage/2))){ + start = numPages - maxPage+1; + } + else{ + start = currPage - Math.floor(maxPage/2); + } + + + bar.innerHTML = ""; + if(currPage>=maxPage){//if more than max, then 1 always exists + bar.innerHTML+="<a class='button1'>1</a>" + bar.innerHTML+="<span class='button1 inactive' disabled>..</span>"; + } + + for(let i=start; i<=(start+maxPage-1);i++){ + if(i>numPages){continue;} + + + if(currPage==i){ + bar.innerHTML+="<a class='Fbutton1 active'>"+i+"</a>" + }else{ + bar.innerHTML+="<a class='button1'>"+i+"</a>" + } + } + if(currPage<numPages-Math.floor(maxPage/2)){// + bar.innerHTML+="<span class='button1 inactive' disabled>..</span>"; + bar.innerHTML+="<a class='button1'>"+numPages+"</a>" + } + + +} +document.addEventListener("DOMContentLoaded", function(){ +generatePagination(200,20,5); +}); \ No newline at end of file diff --git a/src/public/Controller/search.js b/src/public/Controller/search.js new file mode 100644 index 0000000000000000000000000000000000000000..e20689864359f12c901b0c3a278b6776e2148ab5 --- /dev/null +++ b/src/public/Controller/search.js @@ -0,0 +1,143 @@ + + +async function generateHTML(data) { + var counts=0 + var dataContainer = document.getElementById("data-container"); + dataContainer.innerHTML = null; // Clear previous content + + if (data !== null) { + counts=0; + data.forEach(function (item,index) { + // console.log(counts); + var card = document.createElement("div"); + card.className = "card"; + card.id = "song" + item.song_id; + + var img = document.createElement("img"); + img.className = "cardIMG"; + img.src = "http://localhost:8080/storage/images/" + item.image; + + var title = document.createElement("h2"); + title.className = "cardTitle"; + title.textContent = item.judul; + + var author1 = document.createElement("h4"); + author1.className = "cardAuthor"; + author1.textContent = item.penyanyi; + + var author2 = document.createElement("h5"); + author2.className = "cardAuthor"; + author2.textContent = item.year; + + var buttonContainer = document.createElement("div"); + buttonContainer.className = "cardButtonCon"; + + var deleteButton = document.createElement("div"); + deleteButton.className = "playButton delete"; + // deleteButton.textContent = "Delete"; + (function (counts) { + + deleteButton.onclick = function () { + deleteSong(counts); + }; + })(index); + + var editButton = document.createElement("a"); + editButton.href = "/public/song/edit/" + item.song_id; + editButton.className = "playButton edit"; + // editButton.textContent = "Edit"; + + var playButton = document.createElement("div"); + playButton.className = "playButton "; + (function (counts) { + playButton.id = counts; + playButton.onclick = function () { + playStopClick(counts); + }; + })(index); + + buttonContainer.appendChild(deleteButton); + buttonContainer.appendChild(editButton); + buttonContainer.appendChild(playButton); + + card.appendChild(img); + card.appendChild(title); + card.appendChild(author1); + card.appendChild(author2); + card.appendChild(buttonContainer); + + dataContainer.appendChild(card); + counts= counts+1; + }); + } +} + + +const searchBar=document.getElementById("searchBar"); + +searchBar && +searchBar.addEventListener( + "keyup", + debounce(() => { + queryValue = searchBar.value.trim().replace(/[\s\uFEFF\xA0]+/g, '_');; + // queryValue=encodeURIComponent(spaceParam); + // console.log(queryValue); + xhr = new XMLHttpRequest(); + xhr.open( + 'GET', + "/public/song/search/"+queryValue,true + ); + + xhr.setRequestHeader('Content-Type', 'application/json'); + + xhr.onreadystatechange = function () { + if (this.readyState === XMLHttpRequest.DONE) { + // if (this.status === 200) { + // console.log(this.responseText); + const data = JSON.parse(this.responseText); + dataDummy=data; + generateHTML(dataDummy); + // console.log(dataDummy); + isPlayed=false; + + isPause=true; + // lastActivateID=null; + isPlaying=false; + // isPlayed=false; + track_index = 0; + updateTimer; + counts=0 + resetValues(); + + // console.log(data); + // } else { + // alert("An error occured, please try again!"); + // } + } + }; + xhr.send(); + }, 500) +) + +function changeValue(e){ + console.log(e); + filterButton=document.getElementById(e); + console.log(filterButton.value); + + + + if(filterButton.value === "DESCENDING" || filterButton.value==undefined){ + filterButton.value="ASCENDING"; + console.log(filterButton.value); + }else{ + filterButton.value="DESCENDING"; + console.log(filterButton.value); + } + queryValue = searchBar.value.trim(); + if(queryValue === ""){ + queryValue="no" + console.log(queryValue); + } + +} + diff --git a/src/public/Controller/searchController.js b/src/public/Controller/searchController.js new file mode 100644 index 0000000000000000000000000000000000000000..2e9a5052c222d3c318bfdb432e021185c45330ac --- /dev/null +++ b/src/public/Controller/searchController.js @@ -0,0 +1,3 @@ +function handleSubmit(e){ + console.log(e); +} \ No newline at end of file diff --git a/src/public/Controller/signInController.js b/src/public/Controller/signInController.js new file mode 100644 index 0000000000000000000000000000000000000000..e1fe07ddb3983ed900bf49b9fa8bb04feb69a694 --- /dev/null +++ b/src/public/Controller/signInController.js @@ -0,0 +1,67 @@ +// window.location.href("/public/signin"); +document.addEventListener("DOMContentLoaded", function(){ // To halt code before html arrive + +// For now, make it simple +const signInForm = document.getElementById("form-auth"); +const email = document.getElementById("email"); +const password = document.getElementById("password"); + +function resetError(element){ + element.addEventListener("change", function(e){ + e.preventDefault(); + element.style.borderColor = "black"; + }); +} + +resetError(email); +resetError(password); + + +signInForm.addEventListener("submit", function(e){ + let valid = true; + e.preventDefault() + emailVal = email.value; + passwordVal = password.value; + + if(!emailVal){ + console.log("Email empty"); + email.style.borderColor = "red"; + + valid=false; + } + if(!passwordVal){ + console.log("Password empty"); + password.style.borderColor = "red"; + valid=false; + } + + if(!valid){ + return; + } + // Input valid, proceed to request + + + var xhr = new XMLHttpRequest(); + xhr.open("POST", "/public/auth/signin"); + var formData = new FormData(); + formData.append("email",emailVal); + formData.append("password",passwordVal); + + xhr.send(formData); + xhr.onreadystatechange = function () { + if(this.readyState==XMLHttpRequest.DONE){ + if(this.status==201){ //masuk tapi belum diuji + var response = JSON.parse(this.responseText); + location.replace(response.redirect); + }else { + // Error during sign-in + console.error("Sign-in failed. Status code:", xhr.status); + } + } + } +}); +}); +// signInForm.addEventListener("submit",function(e){ +// e.preventDefault(); +// document.getElementById("registerLink").innerText ="Jojo"; +// }); \ No newline at end of file diff --git a/src/public/Controller/signUpController.js b/src/public/Controller/signUpController.js new file mode 100644 index 0000000000000000000000000000000000000000..2717ad80ae3507fe081da92fde157969fef92d18 --- /dev/null +++ b/src/public/Controller/signUpController.js @@ -0,0 +1,106 @@ +/**TODO + * 1. Create Error Message + * 2. Create Response invalid signup + * 3. Create Response valid signup + */ + +document.addEventListener("DOMContentLoaded", function(ev){ // To halt code before html arrive + // For now, make it simple + ev.preventDefault(); + const signUpForm = document.getElementById("form-auth"); + const email = document.getElementById("email"); + const password = document.getElementById("password"); + const confirm = document.getElementById("confirm"); + const username = document.getElementById("username"); + const accessor = [email, password, confirm, username]; + + //add on change event listener + console.log(password); + function isEmptyInput(element){ + if (!element.value.trim()){ + element.style.border = "1px solid red"; + return true; + }else{ + return false; + } + } + signUpForm.addEventListener("submit", function(e){ + //check empty + e.preventDefault(); + first = true; + for(let i =0; i<4; i++){ + if(isEmptyInput(accessor[i])){ + if(first){ + first = false; + //add error message + } + } + } + + //check password and confirm + if(password.value != confirm.value){ + if(first){ + first=false; + //error message + } + confirm.style.border = "red"; + } + + if(!first){ + return; + } + + // all validated, proceed to send request + + var xhr = new XMLHttpRequest(); + xhr.open("POST", "/public/auth/signup"); + var formData = new FormData(); + formData.append("email",email.value); + formData.append("password",password.value); + formData.append("username",username.value); + xhr.send(formData); + xhr.onreadystatechange = function () { + if(this.readyState==XMLHttpRequest.DONE){ + + if(this.status === 201){//valid + const response = JSON.parse(this.responseText); + location.replace(response.redirect_url); + console.log("succeed"); + }else{ + //process what kind of error + if(this.status == 409){ + //process the + const response = JSON.parse(this.responseText); + console.log(response.usernameError); + console.log(response.emailError); + console.log("HUHUHU") + }else{ + console.error("Sign-in failed. Status code:", xhr.status); + } + } + } + } + // if(this.readyState==XMLHttpRequest.DONE){ + // if(this.status==201){ //masuk tapi belum diuji + // var response = JSON.parse(this.responseText); + + // //check apakah response valid + + + // //response valid, proceed to redirect to signin + // location.replace(response.redirect_url); + // }else { + // // Error during sign-in + // console.log(JSON.parse(this.responseText)); + // console.error("Sign-in failed. Status code:", xhr.status); + // } + // } + // } + + }); +}); + + // signInForm.addEventListener("submit",function(e){ + // e.preventDefault(); + // document.getElementById("registerLink").innerText ="Jojo"; + // }); \ No newline at end of file diff --git a/src/public/Controller/song.js b/src/public/Controller/song.js new file mode 100644 index 0000000000000000000000000000000000000000..ad50c5507754248457a67d6c656283426d719e14 --- /dev/null +++ b/src/public/Controller/song.js @@ -0,0 +1,110 @@ +// Add an event listener to the "Upload" button +if(document.getElementById('submitForm')!==null){ + + document.getElementById('submitForm').addEventListener('click', function() { + // Get the form element + var form = document.getElementById('fileUploadForm'); + + // Create a FormData object to gather the form data + var formData = new FormData(form); + + // Log the form data to the console + console.log("Form Data:"); + for (var pair of formData.entries()) { + console.log(pair[0] + ': ' + pair[1]); + } + // Send the form data to the backend PHP script using AJAX + var xhr = new XMLHttpRequest(); + xhr.open('POST', '/public/song/add', true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + // xhr.setRequestHeader("Content-Type", "multipart/form-data"); + + // Set up a callback function to handle the response from the server + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + // Handle the response from the server if needed + console.log(xhr.responseText); + window.location.href = "/public"; + } + }; + xhr.send(formData); + }); +} + +function deleteSong(idx){ + + console.log(dataDummy[idx]); + const formData = new FormData(); + + for (const key in dataDummy[idx]) { + if (dataDummy[idx].hasOwnProperty(key)) { + formData.append(key, dataDummy[idx][key]); + } + } + + // for (const pair of formData.entries()) { + // console.log(pair[0] + ': ' + pair[1]); + // } + + console.log(formData); + var result = confirm("Are you sure you want to delete this item?"); + + // Check the user's choice + if (result === true) { + // The user clicked "OK," so proceed with the deletion + var xhr = new XMLHttpRequest(); + xhr.open('POST', '/public/song/delete', true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + // xhr.setRequestHeader("Content-Type", "multipart/form-data"); + + // Set up a callback function to handle the response from the server + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + // Handle the response from the server if needed + console.log(xhr.responseText); + window.location.href = "/public"; + } + }; + xhr.send(formData); + // alert("Item deleted!"); + // xhr.open('GET', '/public', true); + // You can add your delete logic here + } else { + // The user clicked "Cancel," so do nothing + // alert("Deletion canceled!"); + } +} + +// Add an event listener to the "Upload" button +if(document.getElementById('submitFormEdit')!==null){ + + document.getElementById('submitFormEdit').addEventListener('click', function() { + // Get the form element + var form = document.getElementById('fileUploadFormEdit'); + + // Create a FormData object to gather the form data + var formData = new FormData(form); + var url = new URL(window.location.href); + console.log(url.pathname); + // Log the form data to the console + // console.log("Form Data:"); + for (var pair of formData.entries()) { + console.log(pair[0] + ': ' + pair[1]); + } + // Send the form data to the backend PHP script using AJAX + var xhr = new XMLHttpRequest(); + xhr.open('POST', url.pathname, true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + // xhr.setRequestHeader("Content-Type", "multipart/form-data"); + + // Set up a callback function to handle the response from the server + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + // Handle the response from the server if needed + console.log(xhr.responseText); + window.location.href = "/public"; + } + }; + xhr.send(formData); + }); +} \ No newline at end of file diff --git a/src/public/Controller/userChange.js b/src/public/Controller/userChange.js new file mode 100644 index 0000000000000000000000000000000000000000..9cb1f546f3449fb52d6220b805905011652c9990 --- /dev/null +++ b/src/public/Controller/userChange.js @@ -0,0 +1,12 @@ +const fullnameRegex = /^[a-zA-Z ]+$/; +const usernameRegex = /^\w+$/; +const emailRegex = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; +const passwordRegex = /^\w+$/; + +let fullnameValid = false; +let usernameValid = false; +let emailValid = false; +let passwordValid = false; +let passwordConfirmedValid = false; + diff --git a/src/public/Resources/Assets/CardPNG/back.png b/src/public/Resources/Assets/CardPNG/back.png new file mode 100644 index 0000000000000000000000000000000000000000..c1f9c5a7ff11cfe050572805cc47ea5437ea7d36 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/back.png differ diff --git a/src/public/Resources/Assets/CardPNG/edit.png b/src/public/Resources/Assets/CardPNG/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..5dce8ad9efd7c77bfa48b35e68668c9138868b6b Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/edit.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-delete-60-1.png b/src/public/Resources/Assets/CardPNG/icons8-delete-60-1.png new file mode 100644 index 0000000000000000000000000000000000000000..9b364e90462cf26d2e2ca79ebb8ca48cc2222ebf Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-delete-60-1.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-delete-60-2.png b/src/public/Resources/Assets/CardPNG/icons8-delete-60-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f0da679138197b0ce03e8eac423a3129b94434d Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-delete-60-2.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-delete-60.png b/src/public/Resources/Assets/CardPNG/icons8-delete-60.png new file mode 100644 index 0000000000000000000000000000000000000000..db887652b484dc2e999365c6135691121660631a Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-delete-60.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-multiply-52.png b/src/public/Resources/Assets/CardPNG/icons8-multiply-52.png new file mode 100644 index 0000000000000000000000000000000000000000..78c0ed0d12b5573efd98a07f72a1b0aec9ef7986 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-multiply-52.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-pause-60.png b/src/public/Resources/Assets/CardPNG/icons8-pause-60.png new file mode 100644 index 0000000000000000000000000000000000000000..dc1854ca00b0c1652514d0bf600264380c9c649a Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-pause-60.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-play-50-2.png b/src/public/Resources/Assets/CardPNG/icons8-play-50-2.png new file mode 100644 index 0000000000000000000000000000000000000000..3bbe91074d11eb1b72d92c69d13d4f900d4dd8a9 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-play-50-2.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-play-50-3.png b/src/public/Resources/Assets/CardPNG/icons8-play-50-3.png new file mode 100644 index 0000000000000000000000000000000000000000..467d4ef52005b403a96e1bd2b05164177ae73730 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-play-50-3.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-play-50.png b/src/public/Resources/Assets/CardPNG/icons8-play-50.png new file mode 100644 index 0000000000000000000000000000000000000000..6374f4ec322f9570aeaf00d205b98cc290ad1b92 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-play-50.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-play-60.png b/src/public/Resources/Assets/CardPNG/icons8-play-60.png new file mode 100644 index 0000000000000000000000000000000000000000..ef953c366b2473aecee6f8bd7eee9859f7e62c0d Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-play-60.png differ diff --git a/src/public/Resources/Assets/CardPNG/icons8-x-50.png b/src/public/Resources/Assets/CardPNG/icons8-x-50.png new file mode 100644 index 0000000000000000000000000000000000000000..53cc77b213a945d990e4eff9045eaf887c0348af Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/icons8-x-50.png differ diff --git a/src/public/Resources/Assets/CardPNG/next.png b/src/public/Resources/Assets/CardPNG/next.png new file mode 100644 index 0000000000000000000000000000000000000000..4882c72408265f2d85d28daca4d961621c108b03 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/next.png differ diff --git a/src/public/Resources/Assets/CardPNG/pause.png b/src/public/Resources/Assets/CardPNG/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..3c4de3e0cf7c0885c5ef9e23d6f1d612ed087ad3 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/pause.png differ diff --git a/src/public/Resources/Assets/CardPNG/pause1.png b/src/public/Resources/Assets/CardPNG/pause1.png new file mode 100644 index 0000000000000000000000000000000000000000..f901fcd584b1e9b733cd004d71b2bdf5f601237c Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/pause1.png differ diff --git a/src/public/Resources/Assets/CardPNG/play1.png b/src/public/Resources/Assets/CardPNG/play1.png new file mode 100644 index 0000000000000000000000000000000000000000..f01f7ebaf67b872b96e55e6739fc08f9b392fae3 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/play1.png differ diff --git a/src/public/Resources/Assets/CardPNG/stop.png b/src/public/Resources/Assets/CardPNG/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..b4b5f53695b6c80b85d615ef57a527e1764914f5 Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/stop.png differ diff --git a/src/public/Resources/Assets/CardPNG/stop1.png b/src/public/Resources/Assets/CardPNG/stop1.png new file mode 100644 index 0000000000000000000000000000000000000000..65c0431dce0f770311a0a832e90a61c03070405d Binary files /dev/null and b/src/public/Resources/Assets/CardPNG/stop1.png differ diff --git a/src/public/Resources/Assets/Logo/addAlbum.png b/src/public/Resources/Assets/Logo/addAlbum.png new file mode 100644 index 0000000000000000000000000000000000000000..4bfc6644ade35d49c8656d2fa0763e75752b726c Binary files /dev/null and b/src/public/Resources/Assets/Logo/addAlbum.png differ diff --git a/src/public/Resources/Assets/Logo/addSong.png b/src/public/Resources/Assets/Logo/addSong.png new file mode 100644 index 0000000000000000000000000000000000000000..aae612023cfa85ca91e74e33a6f103cbf2d6dcd7 Binary files /dev/null and b/src/public/Resources/Assets/Logo/addSong.png differ diff --git a/src/public/Resources/Assets/Logo/album.png b/src/public/Resources/Assets/Logo/album.png new file mode 100644 index 0000000000000000000000000000000000000000..e5700af64c6ee0dc68163a2724d49abecaede294 Binary files /dev/null and b/src/public/Resources/Assets/Logo/album.png differ diff --git a/src/public/Resources/Assets/Logo/default_photo_profile.png.png b/src/public/Resources/Assets/Logo/default_photo_profile.png.png new file mode 100644 index 0000000000000000000000000000000000000000..bd07199e06ede3249a5a92540f0b0e118080d98d Binary files /dev/null and b/src/public/Resources/Assets/Logo/default_photo_profile.png.png differ diff --git a/src/public/Resources/Assets/Logo/logo.jpg b/src/public/Resources/Assets/Logo/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d7ac1b34c133672de5abebef35eed8e2844c2915 Binary files /dev/null and b/src/public/Resources/Assets/Logo/logo.jpg differ diff --git a/src/public/Resources/Assets/Logo/logo.png b/src/public/Resources/Assets/Logo/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f499971464ca749db3c956a8fbbdd17069c0d926 Binary files /dev/null and b/src/public/Resources/Assets/Logo/logo.png differ diff --git a/src/public/Resources/Data/dummy.json b/src/public/Resources/Data/dummy.json new file mode 100644 index 0000000000000000000000000000000000000000..e7e570099298ba18e00935b422b1c4975e7108a9 --- /dev/null +++ b/src/public/Resources/Data/dummy.json @@ -0,0 +1,124 @@ +[ + + { + "id":6, + "title":"Shallow", + "author":"Lady Gaga, Bradley Cooper", + "year":2019, + "img":"./Resources/Assets/dataIMG/image14.png", + "song":"./Resources/Assets/Audio/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3" + }, + { + "id":6, + "title":"Shallow", + "author":"Lady Gaga, Bradley Cooper", + "year":2019, + "img":"./Resources/Assets/dataIMG/image14.png", + "song":"./Resources/Assets/Audio/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3" + }, + { + "id":6, + "title":"Shallow", + "author":"Lady Gaga, Bradley Cooper", + "year":2019, + "img":"./Resources/Assets/dataIMG/image14.png", + "song":"./Resources/Assets/Audio/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3" + }, + { + "id":6, + "title":"Shallow", + "author":"Lady Gaga, Bradley Cooper", + "year":2019, + "img":"./Resources/Assets/dataIMG/image14.png", + "song":"./Resources/Assets/Audio/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3" + }, + { + "id":6, + "title":"Shallow", + "author":"Lady Gaga, Bradley Cooper", + "year":2019, + "img":"./Resources/Assets/dataIMG/image14.png", + "song":"./Resources/Assets/Audio/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3" + }, + { + "id":1, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":2, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":3, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":4, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":5, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":6, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":7, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":8, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":9, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + }, + { + "id":10, + "title":"Call Me Maybe", + "author":"Carly Rae Jepsen", + "year":2019, + "img":"./Resources/Assets/dataIMG/download.png", + "song":"./Resources/Assets/Audio/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3" + } + +] \ No newline at end of file diff --git a/src/public/Resources/Styles/addAlbum.css b/src/public/Resources/Styles/addAlbum.css new file mode 100644 index 0000000000000000000000000000000000000000..aa28c19447c8e3643d8d7de3189ce3156e2aad8a --- /dev/null +++ b/src/public/Resources/Styles/addAlbum.css @@ -0,0 +1,119 @@ +body{ + padding: 0%; + margin: 0%; +} +.btn-auth{ + border-radius: 1vh; + background: #243E73; + width: 10vh; + height: 5vh; + flex-shrink: 0; + color: #FFF; + text-align: center; + font-family: Prompt; + font-size: 2.25vh; + font-style: normal; + /* font-weight: 500; */ + line-height: normal; + border: none; + justify-content: center; + justify-self: center; +} +.container-auth{ + padding: 0vh 0vh 8vh 0vh; + display: grid; + position: relative; + grid-template-columns: [first] 2fr [col1] 10fr [col2] 2fr [end]; + grid-template-rows: [row-start] 2fr [row1-end] 10fr [third-line] 2fr [row-end]; + justify-items: center; +} + +.file{ + margin: 10px 0; +} + +.h-auth{ + color: #1C2540; + text-align: center; + font-family: Prompt; + font-size: 3em; + font-style: normal; + font-weight: 600; + line-height: normal; + margin-top: 30px; +} +.label-auth{ + width: 100%; + color: #1C2540; + font-family: Prompt; + font-size: 3vh; + font-style: normal; + font-weight: 500; +} +.box-auth{ + width: 50vh; + height: fit-content; + box-shadow: 0px 0px 10vh 0px rgba(0, 0, 0, 0.25); + border-radius: 5vh; + justify-content: center; + align-items: center; + display: grid; + grid-template-rows: repeat(6, 1fr); + grid-column-start: col1; + grid-column-end: col2; + grid-row-start: row1-end; + grid-row-end: last-line; + align-content: space-evenly; + +} + +.editAlbum{ + grid-template-rows: repeat(4, 1fr); +} +.input-auth{ + padding: 0px 15px; + display: grid; + border-radius: 11px; + background: #FFF; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + height: 3.5vh; + font-size: 1.3em; +} + +.flex{ + /* margin-top: 20px; */ + display: flex; + flex-direction: column; + /* font-size: 20px; */ +} + +.medium{ + width: 40vh; +} + +.container-input-auth{ + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + height: fit-content; +} +.container-input-auth > select{ + height: 50px; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + border-radius: 11px; + font-size: 20px; +} +.container-input-auth > select{ + padding: 0px 10px; + height: 50px; +} +.bottom{ + grid-row-start: -2; +} + +.inputAudio{ + font-size: 20px; +} + +.fileForm{ + /* height: 600px; */ +} \ No newline at end of file diff --git a/src/public/Resources/Styles/addSong.css b/src/public/Resources/Styles/addSong.css new file mode 100644 index 0000000000000000000000000000000000000000..3bb2f0bcafa002b6ecf671bf1b2a3b20cd34cbc6 --- /dev/null +++ b/src/public/Resources/Styles/addSong.css @@ -0,0 +1,116 @@ +body{ + padding: 0%; + margin: 0%; +} +.btn-auth{ + border-radius: 1vh; + background: #243E73; + width: 10vh; + height: 5vh; + flex-shrink: 0; + color: #FFF; + text-align: center; + font-family: Prompt; + font-size: 2.25vh; + font-style: normal; + /* font-weight: 500; */ + line-height: normal; + border: none; + justify-content: center; + justify-self: center; +} + +.file{ + margin: 10px 0; +} + +.container-auth{ + padding: 0vh 0vh 8vh 0vh; + display: grid; + position: relative; + grid-template-columns: [first] 2fr [col1] 10fr [col2] 2fr [end]; + grid-template-rows: [row-start] 2fr [row1-end] 10fr [third-line] 2fr [row-end]; + justify-items: center; +} + +.h-auth{ + color: #1C2540; + text-align: center; + font-family: Prompt; + font-size: 3em; + font-style: normal; + font-weight: 600; + line-height: normal; + margin-top: 30px; +} +.label-auth{ + width: 100%; + color: #1C2540; + font-family: Prompt; + font-size: 3vh; + font-style: normal; + font-weight: 500; +} +.box-auth{ + width: 50vh; + height: fit-content; + box-shadow: 0px 0px 10vh 0px rgba(0, 0, 0, 0.25); + border-radius: 5vh; + justify-content: center; + align-items: center; + display: grid; + grid-template-rows: repeat(8, 1fr); + grid-column-start: col1; + grid-column-end: col2; + grid-row-start: row1-end; + grid-row-end: last-line; + align-content: space-evenly; + +} +.input-auth{ + padding: 0px 15px; + display: grid; + border-radius: 11px; + background: #FFF; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + height: 3.5vh; + font-size: 1.3em; +} + +.flex{ + /* margin-top: 20px; */ + display: flex; + flex-direction: column; + /* font-size: 20px; */ +} + +.medium{ + width: 40vh; +} + +.container-input-auth{ + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + height: fit-content; +} +.container-input-auth > select{ + height: 50px; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + border-radius: 11px; + font-size: 20px; +} +.container-input-auth > select{ + padding: 0px 10px; + height: 50px; +} +.bottom{ + grid-row-start: -2; +} + +.inputAudio{ + font-size: 20px; +} + +.fileForm{ + /* height: 600px; */ +} \ No newline at end of file diff --git a/src/public/Resources/Styles/album.css b/src/public/Resources/Styles/album.css new file mode 100644 index 0000000000000000000000000000000000000000..c0e255fe691bb0ab0a229c8c6aab7ee2b4f39ea3 --- /dev/null +++ b/src/public/Resources/Styles/album.css @@ -0,0 +1,22 @@ +.outerCard{ + height: 361px; + width: 286px; + /* margin: auto; */ + display: flex; + justify-content: center; + align-items: center; +} + +.addAlbum{ + + display: flex; + padding: 0; + margin: 0; + height: 100px; + width: 100px; +} + +.addAlbumIMG{ + height: 100px; + width: 100px; +} diff --git a/src/public/Resources/Styles/body.css b/src/public/Resources/Styles/body.css new file mode 100644 index 0000000000000000000000000000000000000000..60be1bc1b45cb38ac41151554055417eec4f70b9 --- /dev/null +++ b/src/public/Resources/Styles/body.css @@ -0,0 +1,12 @@ +body{ + margin: 0; + padding: 0; + background-color: #b2e0df; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + min-width: 400px; + min-height: 1000px; + overflow: hidden; +} \ No newline at end of file diff --git a/src/public/Resources/Styles/button.css b/src/public/Resources/Styles/button.css new file mode 100644 index 0000000000000000000000000000000000000000..e1f9e004e55ae35f6763e36881de15b1cfe3b30f --- /dev/null +++ b/src/public/Resources/Styles/button.css @@ -0,0 +1,47 @@ +.playButton{ + background-image: url('../Assets/CardPNG/icons8-play-60.png'); + width: 50px; + height: 50px; + background-repeat: no-repeat; + background-size: contain; + transition: 0.1s; +} +.delete{ + background-image: url('../Assets/CardPNG/icons8-multiply-52.png'); + /* transform: scale(0.92); */ + /* width: 40px; + height: 40px; */ + background-size: contain; +} +.edit{ + background-image: url('../Assets/CardPNG/edit.png'); + /* transform: scale(0.92); */ + /* width: 40px; + height: 40px; */ + background-size: contain; +} +.stop{ + background-image: url('../Assets/CardPNG/stop.png'); + background-size: contain; + /* transform: translateY(11px) */ + +} +.pause{ + background-image: url('../Assets/CardPNG/icons8-pause-60.png') ; + background-size: contain; +} +.next{ + background-image: url('../Assets/CardPNG/next.png') ; + background-size: contain; + width: 40px; + height: 40px; +} +.back{ + background-image: url('../Assets/CardPNG/back.png') ; + background-size: contain; + width: 40px; + height: 40px; +} +.playButton:hover{ + cursor:pointer; +} \ No newline at end of file diff --git a/src/public/Resources/Styles/card.css b/src/public/Resources/Styles/card.css new file mode 100644 index 0000000000000000000000000000000000000000..6b358bce763a5878c9df43d1604806e29b79b615 --- /dev/null +++ b/src/public/Resources/Styles/card.css @@ -0,0 +1,66 @@ +.card{ + margin-left: auto; + margin-right: auto; + /* align-items: center; */ + background-color: #efefef; + /* width: 100%; */ + width: 280px; + border-radius: 20px; + height: 312px; + display: table; + text-align: center; + /* justify-content: center; */ + /* padding: auto; */ + padding: 13px 0px; + /* margin-left: auto; + margin-right: auto; */ + color: var(--blueFont); + font-family: Garamond, serif; + /* box-shadow: 0px 3px 2px 2px #000000; */ + box-shadow: 0px 0px 10px 0px var(--blue); + border: 3px solid var(--blueFont); + margin-bottom: -10px; + font-size: 0.85em; +} + +.cardIMG{ + position: relative; + width: 253px; + height: 240px; + border-radius: 12px; + border: 1px solid var(--blueFont); + background-size: contain; + /* margin-left: auto; */ + /* margin-right: auto; */ +} + +.cardTitle{ + text-align: left; + padding-left: 13px; + margin: 5px; +} + +.cardAuthor{ + text-align: left; + padding-left: 13px; + margin: 5px; + color: gray; +} +.cardAuthorAlbum{ + text-align: left; + /* padding-left: 13px; */ + /* margin: 5px; */ + margin: 0; + color: gray; +} + +.cardButtonCon{ + display: flex; + justify-content: space-between; + padding: 0 20px; + align-items: center; +} + +.album{ + height: 280px; +} diff --git a/src/public/Resources/Styles/cardCon.css b/src/public/Resources/Styles/cardCon.css new file mode 100644 index 0000000000000000000000000000000000000000..89ef1896362c5a282c07e79b29cdaa19a70d5dd1 --- /dev/null +++ b/src/public/Resources/Styles/cardCon.css @@ -0,0 +1,196 @@ +:root{ + --blue: #243E73; + --blueFont:#1C2540; + --gray:#EFEFEF; +} + +.cardCon{ + position: relative; + padding-left: 2%; + padding-right: 2%; + /* overflow-y: scroll; */ + /* background-color: #243E73; */ + width: auto; + height: 100%; +} + +.albumCon{ + margin-top: 20px; + /* margin-top: 50px; */ + /* height: 1000px; */ + max-height: 700px; + /* max-height: 1500px; */ +} + +.searchText{ + font-family: 'Courier New',monospace; +} + +.cardCon2{ + height: 70%; +} + +.cardCon3{ + position: relative; + border-radius: 20px; + position: relative; + padding: 0 20px; + padding-top: 25px; + padding-bottom: 40px; + background-color: var(--blueFont); + opacity: 0.98; + box-shadow: 0px 0px 25px 0px #000000; + display: grid; + grid-template-columns: repeat(1,1fr); + /* column-gap: 10px; */ + /* column-gap: 10px; */ + row-gap: 20px; + margin-bottom: -15px; + /* height: 63vh; */ + /* margin-bottom: 20px; */ + height: 60vh; + max-height: 700px; + overflow-y: scroll; + -ms-overflow-style: none; /* Internet Explorer 10+ */ + scrollbar-width: none; /* Firefox */ +} + +.cardCon3::-webkit-scrollbar { + display: none; /* Safari and Chrome */ +} + +@media screen and (max-height: 1180px) and (min-height: 980px){ + .cardCon3{ + height: 60vh; + } + +} +@media screen and (max-height: 980px) and (min-height: 800px){ + .cardCon3{ + height: 50vh; + } +} +@media screen and (max-height: 800px){ + .cardCon3{ + height: 30vh; + } +} +@media screen and (max-height: 400px){ + .cardCon3{ + height: 10vh; + } +} +@media screen and (max-height: 100px){ + .cardCon3{ + height: 10px; + } +}@media screen and (min-width: 4000px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(11,1fr); + column-gap: 10px; + row-gap: 30px; + } +} +@media screen and (min-width: 3600px) and (max-width: 4000px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(10,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (min-width: 3200px) and (max-width: 3600px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(9,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (max-width: 3200px) and (min-width: 2700px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(8,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (max-width: 2700px) and (min-width: 2300px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(7,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (max-width: 2300px) and (min-width: 1880px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(6,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (max-width: 1880px) and (min-width: 1600px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(5,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (max-width: 1600px) and (min-width: 1300px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(4,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} + +@media screen and (max-width: 1300px) and (min-width: 950px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(3,1fr); + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } +} +@media screen and (max-width: 950px) and (min-width: 650px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(2,1fr); + height: 60vh; + max-height: 700px; + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } + .albumCon{ + /* margin-top: 20px; */ + margin-top: 50px; + max-height: 700px; + height: 700px; + /* max-height: 1500px; */ + } +} +@media screen and (max-width: 650px){ + .cardCon3{ + display: grid; + grid-template-columns: repeat(1,1fr); + height: 60vh; + max-height: 700px; + /* column-gap: 10px; */ + /* row-gap: 30px; */ + } + .searchText{ + font-size: 1em; + } + .albumCon{ + /* margin-top: 20px; */ + margin-top: 50px; + max-height: 700px; + height: 700px; + /* max-height: 1500px; */ + } +} \ No newline at end of file diff --git a/src/public/Resources/Styles/filter.css b/src/public/Resources/Styles/filter.css new file mode 100644 index 0000000000000000000000000000000000000000..7740a2242ccf39acab672d64ebbbb8b4e136abe6 --- /dev/null +++ b/src/public/Resources/Styles/filter.css @@ -0,0 +1,57 @@ +.filterCon{ + display: flex; + justify-content: space-between; + align-items: center; + height: 50px; +} +.filterCon2{ + display: flex; + justify-content: space-between; + align-items: center; +} + +.filter{ + /* resize: none; */ + box-shadow: 0px 0px 15px 0px #000000; + align-items: center; + /* min-width: 105px; */ + /* width: 120px; */ + width: auto; + padding: 0 15px; + height: 30px; + border-radius: 20px; + background-color: var(--blue); + margin-block-start: 0.67em; + margin-block-end: 0.67em; + margin-inline-start: 0px; + margin-inline-end: 0px; + /* text-align: center; */ + color: white; + margin: 0 5px; + display: flex; + justify-content: space-between; + cursor: pointer; + /* padding-bottom: 10px; */ + /* margin-top: 30px; */ + /* padding-left: 10px; */ +} + +.filter > h3{ + /* margin:auto auto; */ + cursor: pointer; + margin-right: 5px; +} +.filterText{ + /* padding-top: 4px; + padding-left: 17px; */ + margin: auto 0; + font-family: 'Courier New',monospace; +} + +option{ + background-color: rgb(53, 53, 53); +} + +option:hover{ + /* background-color: var(--blueFont); */ + } \ No newline at end of file diff --git a/src/public/Resources/Styles/login.css b/src/public/Resources/Styles/login.css new file mode 100644 index 0000000000000000000000000000000000000000..6900c712413a0fa7d02413379a4e85b9712aad5a --- /dev/null +++ b/src/public/Resources/Styles/login.css @@ -0,0 +1,100 @@ +body{ + padding: 0%; + margin: 0%; + min-height: 100vh; + width: 100%; +} +.btn-auth{ + border-radius: 1vh; + background: #243E73; + width: 10vh; + height: 5vh; + flex-shrink: 0; + color: #FFF; + text-align: center; + font-family: Prompt; + font-size: 2.25vh; + font-style: normal; + /* font-weight: 500; */ + line-height: normal; + border: none; + justify-content: center; + justify-self: center; + cursor: pointer; +} +.container-auth{ + padding: 8vh 0vh 0vh 0vh; + display: grid; + position: relative; + grid-template-columns: [first] 2fr [col1] 10fr [col2] 2fr [end]; + grid-template-rows: [row-start] 2fr [row1-end] 10fr [third-line] 2fr [row-end]; + justify-items: center; +} +.h-auth{ + color: #1C2540; + text-align: center; + font-family: Prompt; + font-size: 5vh; + font-style: normal; + font-weight: 600; + line-height: normal; +} +.label-auth{ + width: 100%; + color: #1C2540; + font-family: Prompt; + font-size: 3vh; + font-style: normal; + font-weight: 500; +} +.box-auth{ + width: 50vh; + height: 60vh; + box-shadow: 0px 0px 10vh 0px rgba(0, 0, 0, 0.25); + border-radius: 5vh; + justify-content: center; + align-items: center; + display: grid; + grid-template-rows: repeat(7, 1fr); + grid-column-start: col1; + grid-column-end: col2; + grid-row-start: row1-end; + grid-row-end: last-line; + align-content: space-evenly; + +} +.input-auth{ + display: grid; + border-radius: 11px; + background: #FFF; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + height: 3.5vh; + border-color: black; +} + +.medium{ + width: 40vh; +} + +.container-input-auth{ + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + height: 0vh; + justify-content: space-between; +} +.bottom{ + grid-row-start: -2; +} + +.btn-auth:active { + background: #4678dc; +} + +input:focus{ + border-color: #4678dc; +} + +/* .form-auth{ + +} */ + diff --git a/src/public/Resources/Styles/mainCon.css b/src/public/Resources/Styles/mainCon.css new file mode 100644 index 0000000000000000000000000000000000000000..6e4a3b2377f79b132fdcc8d8fc72b08c21daf344 --- /dev/null +++ b/src/public/Resources/Styles/mainCon.css @@ -0,0 +1,23 @@ +:root{ + --blue: #243E73; + --blueFont:#1C2540; + --gray:#EFEFEF; +} + +.mainCon{ + position: relative; + /* background-color: #fefefe; */ + height: 100%; + width: 100%; + display: inline; + justify-content: center; + align-items: center; + /* margin-bottom: 200px; */ + /* overflow-y: scroll; */ + +} + +.searchCon{ + height: 10%; + width: 100%; +} \ No newline at end of file diff --git a/src/public/Resources/Styles/mainPage.css b/src/public/Resources/Styles/mainPage.css new file mode 100644 index 0000000000000000000000000000000000000000..df8798fa1ed3ea6833c1abfc1c61034808589318 --- /dev/null +++ b/src/public/Resources/Styles/mainPage.css @@ -0,0 +1,14 @@ +:root{ + --blue: #243E73; + --blueFont:#1C2540; + --gray:#EFEFEF; +} + +.mainPage{ + background-color: var(--gray); + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; +} \ No newline at end of file diff --git a/src/public/Resources/Styles/navbar.css b/src/public/Resources/Styles/navbar.css new file mode 100644 index 0000000000000000000000000000000000000000..754cddfdecd4f484d84159017bf33ddbd351b1f4 --- /dev/null +++ b/src/public/Resources/Styles/navbar.css @@ -0,0 +1,90 @@ +:root{ + --blue: #243E73; + --blueFont:#1C2540; + --gray:#EFEFEF; + --white:#FFFFFF; +} +a{ + text-decoration: none; +} +.navbar{ + /* padding: 10px; */ + /* padding-left: 30px; + padding-right: 30px; */ + position: relative; + /* top: 0; + left: 0; */ + color: var(--blueFont); + width: 100%; + max-width: 100%; + height: 80px; + background-color: var(--white); + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0px 3px 10px 2px #888888; + gap: 10px; +} + +.h1-WBD{ + position: relative; + +} + +.leftCon{ + /* margin-left: 20px; */ + text-decoration: none; + justify-content: center; + align-items: center; +} +.logoCon{ + /* margin-left: 30px; */ + text-decoration: none; + /* height: 100%; */ + /* width: 100%; */ + margin-left: 30px; +} +.logoimg{ + width: 65px; + height: 65px; + border-radius: 50%; + object-fit: contain; +} +.navbarimg{ + width: 40px; + height: 40px; + margin: auto 10px; + /* padding-right: 30px; */ + /* margin-bottom: 13px; */ + /* border-radius: 50%; */ +} + +.user-icon{ + font-size:0.62em; + /* change font size should change size of icon */ + /* float:left; margin:1em; remove this line to avoid float/margin */ +} + +.avatar{ + width: 60px; + min-width: 60px; + height: 60px; + border-radius: 50%; + background-color: #1C2540; + margin-right: 30px; +} + +.user-icon::before{ + content:" "; display:block; + height:2em; width:2em; + background:skyblue; + position:relative; left:2em;top:0.8em; + border-radius:2em; + } + .user-icon::after{ + content:" "; display:block; + height:2em;width:4em; + background:skyblue; + position:relative; left:1em;top:1em; + border-radius:2em 2em 0 0; + } \ No newline at end of file diff --git a/src/public/Resources/Styles/pagination.css b/src/public/Resources/Styles/pagination.css new file mode 100644 index 0000000000000000000000000000000000000000..98124f45b97714b96418c0e14b70894c0d7e745a --- /dev/null +++ b/src/public/Resources/Styles/pagination.css @@ -0,0 +1,80 @@ + +:root{ + --blue: #243E73; + --blueFont:#1C2540; + --gray:#EFEFEF; +} + +.paginationCon{ + display: flex; + position: relative; + overflow-x: auto; + height: fit-content; + width: 100%; + background-color: var(--blue); + border-radius: 0px 0px 38px 38px; + text-align: center; + justify-content: center; +} +.pagination{ + margin: 0 auto; + position: relative; + z-index: 1000; + /* min-width: 500px; */ + width: 10%; + height: 27px; + display: flex; + flex-wrap: nowrap; + /* overflow-x: auto; */ + background-color: var(--blue); + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + border-radius: 0px 0px 38px 38px; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0); + /* width: 100%; */ + text-align: center; + justify-content: center; +} + +/* ::-webkit-scrollbar { + display: none; + width: 0; +} */ + +.button1 { + font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; + text-align: center; + font-size: 8px; + margin: 0 1px; + /* justify-content: center; */ + flex: 0 0 auto; + width: 20px; + /* padding-top: 3px; */ + /* margin: 3px; */ + /* padding: auto; */ + height: 20px; + /* float: left; */ + /* margin-right: 20px; */ + background-color: #fff; + border: 1px solid; + cursor: pointer; + transition: 0.3s ease width; + z-index: 100; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0); + /* vertical-align: middle; */ + } + +.button1:last-child { + margin-right: 0; + margin-left: 0; +} +.button1.active { + background-color: skyblue; + cursor: default; +} +.inactive{ + cursor: default; +} + + diff --git a/src/public/Resources/Styles/player.css b/src/public/Resources/Styles/player.css new file mode 100644 index 0000000000000000000000000000000000000000..0302a5a7925df2a1f0f19eb011391a7373769f3d --- /dev/null +++ b/src/public/Resources/Styles/player.css @@ -0,0 +1,106 @@ +:root{ + --blue: #243E73; + --blueFont:#1C2540; + --gray:#EFEFEF; +} +.player{ + position: absolute; + width: 100%; + height: 100px; + background-color: white; + bottom: 130px; + z-index: 10; + box-shadow: 0px 3px 10px 2px #888888; + display: flex; + align-items: center; + justify-content: center; +} + +/* .playerCon */ +/* .player > div{ + margin: 0 20px; + width: 30px; + height: 30px; +} */ + +.buttonCon{ + position: relative; + color: var(--blueFont); + align-items: center; + width: 100%; + /* min-width: 150px; */ + display: flex; + height: 50px; + justify-content:center; + font-size: 0.5em; + /* flex-direction: row; */ +} + +.buttonCon > div{ + position: relative; + /* margin: 0 auto; */ + /* margin: 0 auto; */ +} + +.sliderPlayerCon{ + /* margin: auto 20px; */ + display: flex; + flex-direction: column; + width: 50%; + /* padding: 0 auto; */ + margin: 0 auto; + +} +.slider_container { + width: 100%; + /* max-width: 200px; */ + display: flex; + justify-content: center; + align-items: center; + /* margin: 20px; */ + } + + + .seek_slider{ + width: 400px; + } + + .seek_slider, .volume_slider { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 5px; + background: var(--blueFont); + opacity: 0.8; + -webkit-transition: .2s; + transition: opacity .2s; + } + + .seek_slider::-webkit-slider-thumb, +.volume_slider::-webkit-slider-thumb { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + width: 15px; + height: 15px; + background: var(--blueFont); + cursor: pointer; + border-radius: 50%; +} + +.playpause-track, +.prev-track, +.next-track { + padding: 0 25px; + opacity: 0.8; + + /* Smoothly transition the opacity */ + transition: opacity .2s; +} + +/* Change the opacity when mouse is hovered */ +.playpause-track:hover, +.prev-track:hover, +.next-track:hover { + opacity: 1.0; +} \ No newline at end of file diff --git a/src/public/Resources/Styles/searchBar.css b/src/public/Resources/Styles/searchBar.css new file mode 100644 index 0000000000000000000000000000000000000000..2569926b1d15ba64229bcd19bf8c3e45a705587a --- /dev/null +++ b/src/public/Resources/Styles/searchBar.css @@ -0,0 +1,79 @@ +.search-container{ + background-color: #ffffff; + height: 30px; + border-radius: 30px; + padding: 10px 20px; + /* padding-top: 40px; */ + margin-top: 10px; + /* margin-bottom: -10px; */ + margin-left: auto; + margin-right: auto; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: 0.8s; + width: 30px; + box-shadow: 0px 0px 4px 0px #000000 inset; + /*box-shadow:inset 2px 2px 2px 0px rgba(255,255,255,.5), + inset -7px -7px 10px 0px rgba(0,0,0,.1), + 7px 7px 20px 0px rgba(0,0,0,.1), + 4px 4px 5px 0px rgba(0,0,0,.1); + text-shadow: 0px 0px 6px rgba(255,255,255,.3), + -4px -4px 6px rgba(116, 125, 136, .2); + text-shadow: 2px 2px 3px rgba(255,255,255,0.5);*/ + /* box-shadow: 4px 4px 6px 0 rgba(255,255,255,.3), + -4px -4px 6px 0 rgba(116, 125, 136, .2), + inset -4px -4px 6px 0 rgba(255,255,255,.2), + inset 4px 4px 6px 0 rgba(0, 0, 0, .2); */ +} + +.search-container:hover > .search-input{ + /* transition: 1s; */ + color: #1C2540; + width: 100%; +} + +.search-container:active{ + /* transition: 1s; */ + width: 80%; + background-color: #ffffff; +} + +.search-container:hover{ + /* transition: 1s; */ + width: 80%; + background-color: #ffffff; +} + +.search-container:focus{ + /* transition: 1s; */ + width: 80%; + background-color: #ffffff; +} + +.search-container .search-input{ + background: transparent; + border: none; + outline:none; + width: 0px; + font-weight: 500; + font-size: 20px; + transition: 0.5s; +} + +.search-container .search-btn .fas{ + /* background-color: #; */ + color: #1C2540; +} + +/* @keyframes hoverShake { + 0% {transform: skew(0deg,0deg);} + 25% {transform: skew(5deg, 5deg);} + 75% {transform: skew(-5deg, -5deg);} + 100% {transform: skew(0deg,0deg);} +} */ +/* +.search-container:hover{ + animation: hoverShake 0.15s linear 3; +} */ \ No newline at end of file diff --git a/src/public/Resources/Styles/userPage.css b/src/public/Resources/Styles/userPage.css new file mode 100644 index 0000000000000000000000000000000000000000..3b3f1dc614f9f76238ccc62bac27f479bc4d03d0 --- /dev/null +++ b/src/public/Resources/Styles/userPage.css @@ -0,0 +1,151 @@ +* { + color: black; +} + +:root { + --blue: #243E73; + --blueFont: #1C2540; + --gray: #EFEFEF; + --white: #FFFFFF; +} + + +.user-page { + background-color: var(--gray); + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + overflow: auto; +} + +h2 { + padding-left: 30px; + + color: var(--blueFont); + font-family: Prompt, serif; + font-size: 30px; + font-style: normal; + font-weight: 600; + line-height: normal; +} + +/* USER */ +.blue-container { + width: 100%; + display: flex; + justify-content: flex-start; + flex-direction: row; + + padding: 30px 20px; + background-color: var(--blueFont); + border-radius: 40px; + box-shadow: 0 0 29px 0 rgba(0, 0, 0, 0.25); + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.photo-profile-box { + display: flex; + flex-flow: column; + justify-content: space-between; + align-items: center; + width: 25%; + padding-bottom: 20px; +} + +.photo-profile { + border-radius: 50%; + + padding: 0 10px 10px 10px; + width: 250px; + height: 250px; +} + +.button { + border-radius: 24px; + + color: var(--blue); + font-family: Prompt, serif; + font-size: 20px; + font-style: normal; + font-weight: 500; + line-height: normal; +} + +.button:hover { + background-color:dodgerblue; + cursor: pointer; + color: white; + transition: 0.2s; +} + +.user-change-info { + width: 50%; + padding-right: 20px; +} + +.form-change { + display: flex; + justify-content: space-between; + align-items: center; +} + +.form-change label{ + color: var(--white); + font-family: Prompt, serif; + font-size: 16px; + font-style: normal; + font-weight: 500; +} + +.left-column { + display: flex; + flex-direction: column; + padding-right: 20px; +} + +.left-column input { + display: block; + width: 24rem; +} + +.alert-hide-show { + visibility: hidden; + color: #f44336; + margin: 3px 0 20px 0; + + font-family: Prompt, serif; + font-size: 13px; + font-style: normal; +} + +.user-info { + display: flex; + flex-flow: column nowrap; + width: 25%; + padding-left: 20px; +} + +.user-info > .attribute { + margin: 0; + + color: white; + font-family: Prompt, serif; + font-size: 16px; + font-style: normal; + font-weight: 500; +} + +.user-info > .content { + margin: 0 0 40px 0; + + color: white; + font-family: Prompt, serif; + font-size: 20px; + font-style: normal; + font-weight: 500; +} \ No newline at end of file diff --git a/src/public/index.php b/src/public/index.php new file mode 100644 index 0000000000000000000000000000000000000000..990374606451f9f374079ce22bf10896ab329440 --- /dev/null +++ b/src/public/index.php @@ -0,0 +1,6 @@ +<?php + +require_once '../app/init.php'; +ini_set('post_max_size', '40M'); +ini_set('upload_max_filesize', '40M'); +$app = new App; \ No newline at end of file diff --git a/src/storage/images/043914feffcc8f1cd2f763b6902bbfa7.png b/src/storage/images/043914feffcc8f1cd2f763b6902bbfa7.png new file mode 100644 index 0000000000000000000000000000000000000000..e9a9336ee78b16b960b2e11c5bb3001dd84c7856 Binary files /dev/null and b/src/storage/images/043914feffcc8f1cd2f763b6902bbfa7.png differ diff --git a/src/storage/images/0ccc344c300f82d68d84a01186d6e748.jpeg b/src/storage/images/0ccc344c300f82d68d84a01186d6e748.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4065a44a157beced545d59a32833507b62d0a3bb Binary files /dev/null and b/src/storage/images/0ccc344c300f82d68d84a01186d6e748.jpeg differ diff --git a/src/storage/images/2f0aaf1076cd722dcb6cd125d09bac26.jpeg b/src/storage/images/2f0aaf1076cd722dcb6cd125d09bac26.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4065a44a157beced545d59a32833507b62d0a3bb Binary files /dev/null and b/src/storage/images/2f0aaf1076cd722dcb6cd125d09bac26.jpeg differ diff --git a/src/storage/images/3231a54c29f550cadc7968b5578fe3db.jpeg b/src/storage/images/3231a54c29f550cadc7968b5578fe3db.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4065a44a157beced545d59a32833507b62d0a3bb Binary files /dev/null and b/src/storage/images/3231a54c29f550cadc7968b5578fe3db.jpeg differ diff --git a/src/storage/images/40dc2acebc9c689d42f44784cce1e2c7.jpeg b/src/storage/images/40dc2acebc9c689d42f44784cce1e2c7.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..531318f66135209956d91f0b9fae815204e2e102 Binary files /dev/null and b/src/storage/images/40dc2acebc9c689d42f44784cce1e2c7.jpeg differ diff --git a/src/storage/images/42d5673924169392d4e8ec96774c64ca.jpeg b/src/storage/images/42d5673924169392d4e8ec96774c64ca.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..97823e07a12d4909df31beee1ea6a968cfa0fb08 Binary files /dev/null and b/src/storage/images/42d5673924169392d4e8ec96774c64ca.jpeg differ diff --git a/src/storage/images/4fc598a2a5f9705f046f34942db868da.jpeg b/src/storage/images/4fc598a2a5f9705f046f34942db868da.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c5de05ab194211aa46b681ce02d49513e364effc Binary files /dev/null and b/src/storage/images/4fc598a2a5f9705f046f34942db868da.jpeg differ diff --git a/src/storage/images/514418de1634d63ac5e463ab0ed14787.png b/src/storage/images/514418de1634d63ac5e463ab0ed14787.png new file mode 100644 index 0000000000000000000000000000000000000000..6a6db87ead7dbf84d50a64bd800f15c5ab482940 Binary files /dev/null and b/src/storage/images/514418de1634d63ac5e463ab0ed14787.png differ diff --git a/src/storage/images/a1b636766c35d043458d3dd6b264df13.jpeg b/src/storage/images/a1b636766c35d043458d3dd6b264df13.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..879c91ef224072bd4c50557bffeea5f27e5a4fb7 Binary files /dev/null and b/src/storage/images/a1b636766c35d043458d3dd6b264df13.jpeg differ diff --git a/src/storage/images/a574dbaf4e2fa68dcdd255e2c52e919b.jpeg b/src/storage/images/a574dbaf4e2fa68dcdd255e2c52e919b.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4065a44a157beced545d59a32833507b62d0a3bb Binary files /dev/null and b/src/storage/images/a574dbaf4e2fa68dcdd255e2c52e919b.jpeg differ diff --git a/src/storage/images/c5167089ca53596547ea617910e88bb6.jpeg b/src/storage/images/c5167089ca53596547ea617910e88bb6.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4065a44a157beced545d59a32833507b62d0a3bb Binary files /dev/null and b/src/storage/images/c5167089ca53596547ea617910e88bb6.jpeg differ diff --git a/src/storage/images/d4c567e4c03142dea00553c2c91cd177.png b/src/storage/images/d4c567e4c03142dea00553c2c91cd177.png new file mode 100644 index 0000000000000000000000000000000000000000..e9a9336ee78b16b960b2e11c5bb3001dd84c7856 Binary files /dev/null and b/src/storage/images/d4c567e4c03142dea00553c2c91cd177.png differ diff --git a/src/storage/images/d55eb867be7d7b2f13af4bff2e05008d.jpeg b/src/storage/images/d55eb867be7d7b2f13af4bff2e05008d.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..97823e07a12d4909df31beee1ea6a968cfa0fb08 Binary files /dev/null and b/src/storage/images/d55eb867be7d7b2f13af4bff2e05008d.jpeg differ diff --git a/src/storage/images/default_photo_profile.png b/src/storage/images/default_photo_profile.png new file mode 100644 index 0000000000000000000000000000000000000000..bd07199e06ede3249a5a92540f0b0e118080d98d Binary files /dev/null and b/src/storage/images/default_photo_profile.png differ diff --git a/src/storage/images/download.png b/src/storage/images/download.png new file mode 100644 index 0000000000000000000000000000000000000000..c05a235a44efcf616379fdb31e98f6ec218d5a39 Binary files /dev/null and b/src/storage/images/download.png differ diff --git a/src/storage/images/e6b1eb63389563d15d4273c17ead81f3.jpeg b/src/storage/images/e6b1eb63389563d15d4273c17ead81f3.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4065a44a157beced545d59a32833507b62d0a3bb Binary files /dev/null and b/src/storage/images/e6b1eb63389563d15d4273c17ead81f3.jpeg differ diff --git a/src/storage/images/e8296841f86bd2848cb0b643a744935c.png b/src/storage/images/e8296841f86bd2848cb0b643a744935c.png new file mode 100644 index 0000000000000000000000000000000000000000..e9a9336ee78b16b960b2e11c5bb3001dd84c7856 Binary files /dev/null and b/src/storage/images/e8296841f86bd2848cb0b643a744935c.png differ diff --git a/src/storage/images/image10.jpg b/src/storage/images/image10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3d2c4db1c7fdf9ecb1fee62f46977684f8ef514 Binary files /dev/null and b/src/storage/images/image10.jpg differ diff --git a/src/storage/images/image12.png b/src/storage/images/image12.png new file mode 100644 index 0000000000000000000000000000000000000000..0d45f922866d9c20d61e17b6c055fa07ef1849dd Binary files /dev/null and b/src/storage/images/image12.png differ diff --git a/src/storage/images/image14.png b/src/storage/images/image14.png new file mode 100644 index 0000000000000000000000000000000000000000..e9a9336ee78b16b960b2e11c5bb3001dd84c7856 Binary files /dev/null and b/src/storage/images/image14.png differ diff --git a/src/storage/images/image15.jpg b/src/storage/images/image15.jpg new file mode 100644 index 0000000000000000000000000000000000000000..531318f66135209956d91f0b9fae815204e2e102 Binary files /dev/null and b/src/storage/images/image15.jpg differ diff --git a/src/storage/songs/035f4db3f14b8dc243a00e5bd58e7c3b.mp3 b/src/storage/songs/035f4db3f14b8dc243a00e5bd58e7c3b.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/035f4db3f14b8dc243a00e5bd58e7c3b.mp3 differ diff --git a/src/storage/songs/0e2cd598cc3ff338a38c5b45bfe3fa06.mp3 b/src/storage/songs/0e2cd598cc3ff338a38c5b45bfe3fa06.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/0e2cd598cc3ff338a38c5b45bfe3fa06.mp3 differ diff --git a/src/storage/songs/14b20fa85eb3a725623fe15812844a53.mp3 b/src/storage/songs/14b20fa85eb3a725623fe15812844a53.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/14b20fa85eb3a725623fe15812844a53.mp3 differ diff --git a/src/storage/songs/1512ce37a0992273b661fc5605ca31cc.mp3 b/src/storage/songs/1512ce37a0992273b661fc5605ca31cc.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..7fc1c33e6aae769c90740d064cf4bd905778adc0 Binary files /dev/null and b/src/storage/songs/1512ce37a0992273b661fc5605ca31cc.mp3 differ diff --git a/src/storage/songs/268cfc826d84061ce904c44f5aa08047.mp3 b/src/storage/songs/268cfc826d84061ce904c44f5aa08047.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/268cfc826d84061ce904c44f5aa08047.mp3 differ diff --git a/src/storage/songs/2c671e4f4ebbb55f8431f7c230d00bf0.mp3 b/src/storage/songs/2c671e4f4ebbb55f8431f7c230d00bf0.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/2c671e4f4ebbb55f8431f7c230d00bf0.mp3 differ diff --git a/src/storage/songs/6530d975d2183800b90a93e8b5a7bcd7.mp3 b/src/storage/songs/6530d975d2183800b90a93e8b5a7bcd7.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..9a4fb54c7f846a76f8cda3770490b843aa2333fd Binary files /dev/null and b/src/storage/songs/6530d975d2183800b90a93e8b5a7bcd7.mp3 differ diff --git a/src/storage/songs/71f2b91657ffb9f4c9331d75f1ccab2b.mp3 b/src/storage/songs/71f2b91657ffb9f4c9331d75f1ccab2b.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..508966bd0a709dd1474189a1bbcf52e7a4aba3d0 Binary files /dev/null and b/src/storage/songs/71f2b91657ffb9f4c9331d75f1ccab2b.mp3 differ diff --git a/src/storage/songs/8d7c41bdf353ff9038788c26fddd5c9e.mp3 b/src/storage/songs/8d7c41bdf353ff9038788c26fddd5c9e.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/8d7c41bdf353ff9038788c26fddd5c9e.mp3 differ diff --git a/src/storage/songs/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3 b/src/storage/songs/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/Carly_Rae_Jepsen_-_Call_Me_Maybe_.mp3 differ diff --git a/src/storage/songs/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3 b/src/storage/songs/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3 new file mode 100644 index 0000000000000000000000000000000000000000..edc802e56a36a7d516590339b3f21895f63f7267 Binary files /dev/null and b/src/storage/songs/Lady Gaga Bradley Cooper - Shallow (Lyrics) (A Star Is Born Soundtrack).mp3 differ diff --git a/src/storage/songs/add8a2fc7b85a76f94ba48b2c186586d.mp3 b/src/storage/songs/add8a2fc7b85a76f94ba48b2c186586d.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/add8a2fc7b85a76f94ba48b2c186586d.mp3 differ diff --git a/src/storage/songs/bf566d2b1522801a3e23e631b432347c.mp3 b/src/storage/songs/bf566d2b1522801a3e23e631b432347c.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..9a4fb54c7f846a76f8cda3770490b843aa2333fd Binary files /dev/null and b/src/storage/songs/bf566d2b1522801a3e23e631b432347c.mp3 differ diff --git a/src/storage/songs/c80ea8938c8a93a5b55e953232221326.mp3 b/src/storage/songs/c80ea8938c8a93a5b55e953232221326.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/c80ea8938c8a93a5b55e953232221326.mp3 differ diff --git a/src/storage/songs/e4f3a6ed756a6ea59414567b77e56f93.mp3 b/src/storage/songs/e4f3a6ed756a6ea59414567b77e56f93.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a1c178594858d9cb088400f319c3533a2fcfe466 Binary files /dev/null and b/src/storage/songs/e4f3a6ed756a6ea59414567b77e56f93.mp3 differ diff --git a/src/storage/songs/song2.mp3 b/src/storage/songs/song2.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d3e8dfa25aac5344b20f37169446bbedfcb5503f Binary files /dev/null and b/src/storage/songs/song2.mp3 differ