diff --git a/app.py b/app.py index 36721a06..7eaa8af3 100644 --- a/app.py +++ b/app.py @@ -1,14 +1,63 @@ -import os -from flask import Flask +from flask import Flask, render_template, request, redirect, url_for, session, flash + app = Flask(__name__) +app.secret_key = 'rahasia123' + +# Simulasi database +USERS = {'admin': 'admin123'} +ITEMS = [] # Menyimpan item berupa dict {'name': ..., 'description': ...} + +@app.route('/') +def index(): + if 'user' in session: + return redirect(url_for('dashboard')) + return redirect(url_for('login')) + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + if USERS.get(username) == password: + session['user'] = username + return redirect(url_for('dashboard')) + else: + flash("Login gagal! Username atau password salah.") + return render_template('login.html') + +@app.route('/dashboard') +def dashboard(): + if 'user' not in session: + return redirect(url_for('login')) + return render_template('dashboard.html', items=ITEMS) + +@app.route('/create', methods=['GET', 'POST']) +def create(): + if 'user' not in session: + return redirect(url_for('login')) + + if request.method == 'POST': + name = request.form.get('name', '').strip() + description = request.form.get('description', '').strip() + + if name and description: + ITEMS.append({'name': name, 'description': description}) + return redirect(url_for('success')) + else: + flash("Semua field wajib diisi!") + + return render_template('create.html') -@app.route("/") -def main(): - return "Welcome!" +@app.route('/success') +def success(): + if 'user' not in session: + return redirect(url_for('login')) + return render_template('success.html') -@app.route('/how are you') -def hello(): - return 'I am good, how about you?' +@app.route('/logout') +def logout(): + session.pop('user', None) + return render_template('logout.html') -if __name__ == "__main__": - app.run(host="0.0.0.0", port=8080) +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=5000) diff --git a/docs/uml/class-diagram.puml b/docs/uml/class-diagram.puml new file mode 100644 index 00000000..94f50f04 --- /dev/null +++ b/docs/uml/class-diagram.puml @@ -0,0 +1,35 @@ +@startuml + +class User { + +id: int + +username: str + +email: str + +password: str +} + +class RegisterForm { + +username: str + +email: str + +password: str + +submit(): void +} + +class LoginForm { + +username: str + +password: str + +submit(): void +} + +class Item { + +id: int + +name: str + +description: str + +price: float + +create(): void +} + +User "1" --> "*" Item : owns +RegisterForm ..> User : <> +LoginForm ..> User : <> + +@enduml \ No newline at end of file diff --git a/docs/uml/sequence-create-item.puml b/docs/uml/sequence-create-item.puml new file mode 100644 index 00000000..cb54285a --- /dev/null +++ b/docs/uml/sequence-create-item.puml @@ -0,0 +1,13 @@ +@startuml sequence-create-item +actor User +participant "Create Item Page" as ItemPage +participant "routes.py" as Route +participant "models.py" as ItemModel + +User -> ItemPage : open form +User -> ItemPage : input item data +ItemPage -> Route : POST /create +Route -> ItemModel : save new item +ItemModel --> Route : success +Route --> ItemPage : show confirmation +@enduml diff --git a/docs/uml/sequence-login.puml b/docs/uml/sequence-login.puml new file mode 100644 index 00000000..6f64e8eb --- /dev/null +++ b/docs/uml/sequence-login.puml @@ -0,0 +1,17 @@ +@startuml sequence-login +actor User +participant "Login Page" as LoginPage +participant "routes.py" as Route +participant "models.py" as UserModel + +User -> LoginPage : open form +User -> LoginPage : input username & password +LoginPage -> Route : POST /login +Route -> UserModel : validate_user() +UserModel --> Route : user exists or not +alt valid + Route --> LoginPage : redirect to dashboard +else invalid + Route --> LoginPage : show error +end +@enduml \ No newline at end of file diff --git a/evaluasi/pull-request/Cuplikan layar 2025-06-29 140057.png b/evaluasi/pull-request/Cuplikan layar 2025-06-29 140057.png new file mode 100644 index 00000000..d2713d68 Binary files /dev/null and b/evaluasi/pull-request/Cuplikan layar 2025-06-29 140057.png differ diff --git a/evaluasi/pull-request/blackbox/blackbox_test.side b/evaluasi/pull-request/blackbox/blackbox_test.side new file mode 100644 index 00000000..85a4bfd9 --- /dev/null +++ b/evaluasi/pull-request/blackbox/blackbox_test.side @@ -0,0 +1,219 @@ +{ + "id": "f0cc3a3c-3756-41c4-b840-a7b76891999a", + "version": "2.0", + "name": "BlackboxTest", + "url": "https://musical-orbit-v6ggwwr7j5vpcx5g5-5000.app.github.dev", + "tests": [{ + "id": "d8dbcc04-7dae-4d8c-81e1-18dcf1ef3343", + "name": "blacboxtest", + "commands": [{ + "id": "529828f6-aabc-4c75-af03-64aa6d3fbfeb", + "comment": "", + "command": "open", + "target": "/", + "targets": [], + "value": "" + }, { + "id": "0814ce74-32c9-44e4-8891-cd0ca5aab66b", + "comment": "", + "command": "setWindowSize", + "target": "1280x691", + "targets": [], + "value": "" + }, { + "id": "d67fa136-0241-4a79-b76c-45890b029419", + "comment": "", + "command": "click", + "target": "css=.btn-primary", + "targets": [ + ["css=.btn-primary", "css:finder"], + ["xpath=//button[@type='submit']", "xpath:attributes"], + ["xpath=//button", "xpath:position"], + ["xpath=//button[contains(.,'Continue')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "357a75a0-7c1c-4e9d-a763-9a5e5eb6a811", + "comment": "", + "command": "click", + "target": "css=form", + "targets": [ + ["css=form", "css:finder"], + ["xpath=//form", "xpath:position"] + ], + "value": "" + }, { + "id": "74cd534c-7f2d-4c62-acdd-012b7713baaf", + "comment": "", + "command": "click", + "target": "name=username", + "targets": [ + ["name=username", "name"], + ["css=input:nth-child(2)", "css:finder"], + ["xpath=//input[@name='username']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "" + }, { + "id": "6f234b0f-f4de-4f45-8cd3-321512e8616e", + "comment": "", + "command": "type", + "target": "name=username", + "targets": [ + ["name=username", "name"], + ["css=input:nth-child(2)", "css:finder"], + ["xpath=//input[@name='username']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "admin" + }, { + "id": "6414d6a7-c871-4e29-87a9-da8a42caf573", + "comment": "", + "command": "click", + "target": "name=password", + "targets": [ + ["name=password", "name"], + ["css=input:nth-child(6)", "css:finder"], + ["xpath=//input[@name='password']", "xpath:attributes"], + ["xpath=//input[2]", "xpath:position"] + ], + "value": "" + }, { + "id": "88bcfaaf-e083-45dd-8396-804709ad90cc", + "comment": "", + "command": "type", + "target": "name=password", + "targets": [ + ["name=password", "name"], + ["css=input:nth-child(6)", "css:finder"], + ["xpath=//input[@name='password']", "xpath:attributes"], + ["xpath=//input[2]", "xpath:position"] + ], + "value": "admin123" + }, { + "id": "449cdba6-19c6-46a6-b190-ca2969899da2", + "comment": "", + "command": "click", + "target": "css=button", + "targets": [ + ["css=button", "css:finder"], + ["xpath=//button[@type='submit']", "xpath:attributes"], + ["xpath=//button", "xpath:position"], + ["xpath=//button[contains(.,'Login')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "07b52b82-9b29-4736-a0d3-dcecedade6ba", + "comment": "", + "command": "click", + "target": "linkText=Tambah Item", + "targets": [ + ["linkText=Tambah Item", "linkText"], + ["css=.button:nth-child(2)", "css:finder"], + ["xpath=//a[contains(text(),'Tambah Item')]", "xpath:link"], + ["xpath=//a[contains(@href, '/create')]", "xpath:href"], + ["xpath=//a", "xpath:position"], + ["xpath=//a[contains(.,'Tambah Item')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "6b62c302-03cb-46d2-8718-7104cfa8d621", + "comment": "", + "command": "click", + "target": "name=name", + "targets": [ + ["name=name", "name"], + ["css=input:nth-child(2)", "css:finder"], + ["xpath=//input[@name='name']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "" + }, { + "id": "799dd1e7-7a85-4298-917f-7f05f70433cf", + "comment": "", + "command": "type", + "target": "name=name", + "targets": [ + ["name=name", "name"], + ["css=input:nth-child(2)", "css:finder"], + ["xpath=//input[@name='name']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "kudalumping" + }, { + "id": "e48743fb-8d04-4585-a54b-b48994fa5e9b", + "comment": "", + "command": "click", + "target": "name=description", + "targets": [ + ["name=description", "name"], + ["css=input:nth-child(6)", "css:finder"], + ["xpath=//input[@name='description']", "xpath:attributes"], + ["xpath=//input[2]", "xpath:position"] + ], + "value": "" + }, { + "id": "2668910a-8a18-4292-bc41-6f2bf022d28f", + "comment": "", + "command": "type", + "target": "name=description", + "targets": [ + ["name=description", "name"], + ["css=input:nth-child(6)", "css:finder"], + ["xpath=//input[@name='description']", "xpath:attributes"], + ["xpath=//input[2]", "xpath:position"] + ], + "value": "asliwonogiri" + }, { + "id": "a5c83a42-4171-47d0-9135-cf48b13f552d", + "comment": "", + "command": "click", + "target": "css=button", + "targets": [ + ["css=button", "css:finder"], + ["xpath=//button[@type='submit']", "xpath:attributes"], + ["xpath=//button", "xpath:position"], + ["xpath=//button[contains(.,'Simpan')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "d3a14603-9eed-43ad-8edf-35a41d478f4a", + "comment": "", + "command": "click", + "target": "linkText=Kembali ke Dashboard", + "targets": [ + ["linkText=Kembali ke Dashboard", "linkText"], + ["css=a", "css:finder"], + ["xpath=//a[contains(text(),'Kembali ke Dashboard')]", "xpath:link"], + ["xpath=//a[contains(@href, '/dashboard')]", "xpath:href"], + ["xpath=//a", "xpath:position"], + ["xpath=//a[contains(.,'Kembali ke Dashboard')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "4a8a5c9f-5f58-4d1c-8c4c-11916b07dd91", + "comment": "", + "command": "click", + "target": "linkText=Logout", + "targets": [ + ["linkText=Logout", "linkText"], + ["css=.button:nth-child(3)", "css:finder"], + ["xpath=//a[contains(text(),'Logout')]", "xpath:link"], + ["xpath=//a[contains(@href, '/logout')]", "xpath:href"], + ["xpath=//a[2]", "xpath:position"], + ["xpath=//a[contains(.,'Logout')]", "xpath:innerText"] + ], + "value": "" + }] + }], + "suites": [{ + "id": "1584523a-6821-4259-bf74-26b19bec3f2f", + "name": "Default Suite", + "persistSession": false, + "parallel": false, + "timeout": 300, + "tests": ["d8dbcc04-7dae-4d8c-81e1-18dcf1ef3343"] + }], + "urls": ["https://musical-orbit-v6ggwwr7j5vpcx5g5-5000.app.github.dev/"], + "plugins": [] +} \ No newline at end of file diff --git a/evaluasi/pull-request/blackbox/readme.md b/evaluasi/pull-request/blackbox/readme.md new file mode 100644 index 00000000..8d0ab689 --- /dev/null +++ b/evaluasi/pull-request/blackbox/readme.md @@ -0,0 +1,10 @@ +## Black-box Testing โ€“ Selenium + +**Skenario yang diuji:** +1. Login dengan akun valid +2. Menambahkan data item baru +3. Logout + +**Hasil:** +Semua skenario berhasil dijalankan (PASS) +Terekam dalam file `blackbox_test.side` diff --git a/evaluasi/pull-request/lisensi/README.md b/evaluasi/pull-request/lisensi/README.md new file mode 100644 index 00000000..64b60211 --- /dev/null +++ b/evaluasi/pull-request/lisensi/README.md @@ -0,0 +1,23 @@ +# ๐Ÿ” Etika & Lisensi + +## Lisensi Proyek Asli +Proyek asli yang saya fork menggunakan **MIT License**. + +## Perubahan yang Saya Lakukan +- Menambahkan fitur login dan tambah data item +- Membuat diagram UML dan pengujian black-box +- Melakukan usability study + +## Kompatibilitas Lisensi +MIT License sangat permisif: +- Memperbolehkan perubahan dan redistribusi +- Tidak mewajibkan publikasi perubahan +- Hanya meminta mencantumkan atribusi + +โœ… **Perubahan saya 100% kompatibel dengan MIT License** + +## Etika Open Source +Saya tetap: +- Mencantumkan nama pembuat asli di bagian lisensi +- Tidak menghapus hak cipta +- Menambahkan dokumentasi perubahan yang dilakukan diff --git a/evaluasi/pull-request/sus/README.md b/evaluasi/pull-request/sus/README.md new file mode 100644 index 00000000..d900e5eb --- /dev/null +++ b/evaluasi/pull-request/sus/README.md @@ -0,0 +1,25 @@ +# ๐Ÿ“Š Usability Study โ€“ System Usability Scale (SUS) + +## ๐Ÿ”— Aplikasi yang diuji +https://musical-orbit-v6ggwwr7j5vpcx5g5-5000.app.github.dev/ + +## ๐Ÿงช Metode +- Metode: System Usability Scale (SUS) +- Total Pertanyaan: 10 +- Skala: 1 (Sangat Tidak Setuju) โ€“ 5 (Sangat Setuju) +- Responden: 3 orang + +## ๐Ÿงฎ Skor +- Responden 1: 85.0 +- Responden 2: 77.5 +- Responden 3: 80.0 +- **Rata-rata SUS = 80.8** + +## โœ… Interpretasi +- Rata-rata skor SUS 80.8 berada di kategori **โ€œExcellentโ€**. +- Aplikasi dianggap mudah dipakai, konsisten, dan tidak membingungkan. + +## ๐Ÿ“Š Grafik +(Lampirkan tangkapan grafik Google Form โ€“ atau export sebagai PNG) + +## ๐Ÿ“ Struktur Folder diff --git a/evaluasi/pull-request/sus/hasil_sus.png b/evaluasi/pull-request/sus/hasil_sus.png new file mode 100644 index 00000000..f3dc1d8e Binary files /dev/null and b/evaluasi/pull-request/sus/hasil_sus.png differ diff --git a/out/docs/uml/class-diagram/class-diagram.png b/out/docs/uml/class-diagram/class-diagram.png new file mode 100644 index 00000000..b26ed787 Binary files /dev/null and b/out/docs/uml/class-diagram/class-diagram.png differ diff --git a/out/docs/uml/sequence-create-item/sequence-create-item.png b/out/docs/uml/sequence-create-item/sequence-create-item.png new file mode 100644 index 00000000..f8064c56 Binary files /dev/null and b/out/docs/uml/sequence-create-item/sequence-create-item.png differ diff --git a/out/docs/uml/sequence-login/sequence-login.png b/out/docs/uml/sequence-login/sequence-login.png new file mode 100644 index 00000000..4d695a10 Binary files /dev/null and b/out/docs/uml/sequence-login/sequence-login.png differ diff --git a/templates/create.html b/templates/create.html new file mode 100644 index 00000000..8e9ce676 --- /dev/null +++ b/templates/create.html @@ -0,0 +1,18 @@ + + + + Tambah Item + + +

Form Tambah Item

+
+ +

+ +

+ +
+
+ Kembali ke Dashboard + + diff --git a/templates/dashboard.html b/templates/dashboard.html new file mode 100644 index 00000000..5395205d --- /dev/null +++ b/templates/dashboard.html @@ -0,0 +1,35 @@ + + + + Dashboard + + + +

Selamat Datang, {{ session['user'] }}

+ + Tambah Item + Logout + +

Daftar Item:

+ + + diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 00000000..9893ae48 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,15 @@ + + +Login + +

Login

+
+ +

+ +

+ +
+ + + diff --git a/templates/logout.html b/templates/logout.html new file mode 100644 index 00000000..0c978891 --- /dev/null +++ b/templates/logout.html @@ -0,0 +1,8 @@ + + +Logout + +

Anda telah logout.

+ Login lagi + + diff --git a/templates/success.html b/templates/success.html new file mode 100644 index 00000000..6dbba71e --- /dev/null +++ b/templates/success.html @@ -0,0 +1,8 @@ + + +Sukses + +

Item berhasil ditambahkan!

+ Kembali ke Dashboard + +