diff --git a/Model/Bill.php b/Model/Bill.php
new file mode 100644
index 0000000..caff8fa
--- /dev/null
+++ b/Model/Bill.php
@@ -0,0 +1,21 @@
+id = $id;
+ $this->dueDate = $dueDate;
+ $this->amount = $amount;
+ $this->description = $description;
+ $this->isPaid = $isPaid;
+ }
+
+ // Additional methods as needed, such as getters and setters
+}
diff --git a/Model/User.php b/Model/User.php
new file mode 100644
index 0000000..4e8e3ca
--- /dev/null
+++ b/Model/User.php
@@ -0,0 +1,20 @@
+id = $id;
+ $this->username = $username;
+ $this->passwordHash = $passwordHash;
+ }
+
+ // Add methods for password verification, etc.
+ public function verifyPassword(string $password): bool {
+ return password_verify($password, $this->passwordHash);
+ }
+}
diff --git a/Service/BillManager.php b/Service/BillManager.php
new file mode 100644
index 0000000..bd6aa4e
--- /dev/null
+++ b/Service/BillManager.php
@@ -0,0 +1,69 @@
+db = $db;
+ }
+
+ public function createBill(Bill $bill): bool {
+ $sql = "INSERT INTO bills (dueDate, amount, description, isPaid) VALUES (:dueDate, :amount, :description, :isPaid)";
+ $this->db->prepare($sql);
+ $this->db->execute([
+ ':dueDate' => $bill->dueDate,
+ ':amount' => $bill->amount,
+ ':description' => $bill->description,
+ ':isPaid' => $bill->isPaid ? 1 : 0,
+ ]);
+ return $this->db->lastInsertId() > 0;
+ }
+
+ public function getBill(int $id): ?Bill {
+ $sql = "SELECT * FROM bills WHERE id = :id";
+ $this->db->prepare($sql);
+ $this->db->execute([':id' => $id]);
+ $result = $this->db->fetch();
+ if ($result) {
+ return new Bill($result['id'], $result['dueDate'], $result['amount'], $result['description'], $result['isPaid'] == 1);
+ }
+ return null;
+ }
+
+
+ public function updateBill(Bill $bill): bool {
+ $sql = "UPDATE bills SET dueDate = :dueDate, amount = :amount, description = :description, isPaid = :isPaid WHERE id = :id";
+ $this->db->prepare($sql);
+ return $this->db->execute([
+ ':id' => $bill->id,
+ ':dueDate' => $bill->dueDate,
+ ':amount' => $bill->amount,
+ ':description' => $bill->description,
+ ':isPaid' => $bill->isPaid ? 1 : 0,
+ ]);
+ }
+
+
+ public function deleteBill(int $id): bool {
+ $sql = "DELETE FROM bills WHERE id = :id";
+ $this->db->prepare($sql);
+ return $this->db->execute([':id' => $id]);
+ }
+
+
+ public function listBills(): array {
+ $sql = "SELECT * FROM bills";
+ $this->db->prepare($sql);
+ $this->db->execute();
+ $bills = [];
+ while ($row = $this->db->fetch()) {
+ $bills[] = new Bill($row['id'], $row['dueDate'], $row['amount'], $row['description'], $row['isPaid'] == 1);
+ }
+ return $bills;
+ }
+}
diff --git a/Service/UserManager.php b/Service/UserManager.php
new file mode 100644
index 0000000..66606cd
--- /dev/null
+++ b/Service/UserManager.php
@@ -0,0 +1,42 @@
+db = $db;
+ }
+
+ public function register(string $username, string $password): bool {
+ $passwordHash = password_hash($password, PASSWORD_DEFAULT);
+
+ $sql = "INSERT INTO users (username, passwordHash) VALUES (:username, :passwordHash)";
+ $this->db->prepare($sql);
+ return $this->db->execute([
+ ':username' => $username,
+ ':passwordHash' => $passwordHash,
+ ]);
+ }
+
+ public function login(string $username, string $password): ?User {
+ $sql = "SELECT * FROM users WHERE username = :username";
+ $this->db->prepare($sql);
+ $this->db->execute([':username' => $username]);
+ $result = $this->db->fetch();
+
+ if ($result && (new User($result['id'], $result['username'], $result['passwordHash']))->verifyPassword($password)) {
+ // Start or regenerate the session
+ session_regenerate_id();
+ $_SESSION['user_id'] = $result['id'];
+ return new User($result['id'], $result['username'], $result['passwordHash']);
+ }
+
+ return null;
+ }
+
+ // Additional methods as needed, e.g., for password change, user details update, etc.
+}
diff --git a/View/PageRenderer.php b/View/PageRenderer.php
new file mode 100644
index 0000000..a83ae65
--- /dev/null
+++ b/View/PageRenderer.php
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ $title
+
+
+
+
+
+HTML;
+ }
+
+ public static function renderFooter() {
+ echo <<
+
+
+
+
+
+HTML;
+ }
+}
diff --git a/composer.json b/composer.json
index b22cd92..700713b 100644
--- a/composer.json
+++ b/composer.json
@@ -13,5 +13,12 @@
"email": "hpz937+code@gmail.com"
}
],
- "require": {}
+ "repositories": [{
+ "type": "composer",
+ "url": "https://git.hpz.pw/api/packages/hpz937/composer"
+ }
+ ],
+ "require": {
+ "hpz937/restclient": "1.0.0"
+ }
}
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..6609e75
--- /dev/null
+++ b/index.php
@@ -0,0 +1,27 @@
+connect();
+
+$databaseSetup = new DatabaseSetup($db);
+$databaseSetup->setup();
+
+// Continue with the rest of your application setup
diff --git a/src/Database/DatabaseInterface.php b/src/Database/DatabaseInterface.php
new file mode 100644
index 0000000..9a715c9
--- /dev/null
+++ b/src/Database/DatabaseInterface.php
@@ -0,0 +1,14 @@
+db = $db;
+ }
+
+ public function setup(): void {
+ $this->createBillsTable();
+ $this->createUsersTable();
+ }
+
+ private function createBillsTable(): void {
+ $sql = <<
db->query($sql);
+ }
+
+ private function createUsersTable(): void {
+ $sql = <<db->query($sql);
+ }
+
+ // Additional methods to setup other tables as needed
+}
diff --git a/src/Database/SQLite3Database.php b/src/Database/SQLite3Database.php
new file mode 100644
index 0000000..98866d5
--- /dev/null
+++ b/src/Database/SQLite3Database.php
@@ -0,0 +1,83 @@
+databaseFile = $databaseFile;
+ }
+
+ public function connect() {
+ try {
+ $this->connection = new SQLite3($this->databaseFile);
+ } catch (Exception $e) {
+ throw new Exception("Unable to connect to SQLite database: " . $e->getMessage());
+ }
+ }
+
+ public function query(string $query) {
+ if (!$this->connection) {
+ throw new Exception("No database connection");
+ }
+ return $this->connection->query($query);
+ }
+
+ public function prepare(string $sql) {
+ if (!$this->connection) {
+ throw new Exception("No database connection");
+ }
+ $this->statement = $this->connection->prepare($sql);
+ if (!$this->statement) {
+ throw new Exception("Failed to prepare SQL statement");
+ }
+ }
+
+ public function execute(array $parameters = []) {
+ if (!$this->statement) {
+ throw new Exception("No prepared statement");
+ }
+ foreach ($parameters as $param => $value) {
+ $this->statement->bindValue($param, $value);
+ }
+ return $this->statement->execute();
+ }
+
+ public function fetch() {
+ if (!$this->statement) {
+ throw new Exception("No prepared statement");
+ }
+ return $this->statement->fetchArray(SQLITE3_ASSOC);
+ }
+
+ public function fetchAll() {
+ $data = [];
+ while ($row = $this->fetch()) {
+ $data[] = $row;
+ }
+ return $data;
+ }
+
+ public function close() {
+ if ($this->connection) {
+ $this->connection->close();
+ }
+ }
+}
diff --git a/src/Notification/NftyNotification.php b/src/Notification/NftyNotification.php
new file mode 100644
index 0000000..50e8c98
--- /dev/null
+++ b/src/Notification/NftyNotification.php
@@ -0,0 +1,44 @@
+restClient = $restClient;
+ }
+
+ public function send(string $to, string $message, array $options = []): bool {
+ try {
+ // ntfy.sh uses simple text/plain content type for the message body
+ $headers = ["Content-Type: text/plain"];
+ if (isset($options['title'])) {
+ $headers[] = "Title: {$options['title']}";
+ }
+ if (isset($options['priority'])) {
+ $headers[] = "Priority: {$options['priority']}";
+ }
+ if (isset($options['tags'])) {
+ $headers[] = "Tags: {$options['tags']}";
+ }
+
+ $this->restClient->setHeaders($headers);
+
+ // Use the RestClient's custom request method to mimic the file_get_contents approach
+ $this->restClient->post("https://ntfy.sh/{$this->to}", $message);
+
+ // Since ntfy.sh returns a simple response, we might not need to decode JSON
+ $response = $this->restClient->getResponse();
+
+ // Check the response or HTTP status code as needed to determine success
+ return true; // Assuming the request was successful, adjust based on actual response handling
+ } catch (Exception $e) {
+ // Error handling logic
+ return false;
+ }
+ }
+}
diff --git a/src/Notification/NotificationInterface.php b/src/Notification/NotificationInterface.php
new file mode 100644
index 0000000..51f5b48
--- /dev/null
+++ b/src/Notification/NotificationInterface.php
@@ -0,0 +1,15 @@
+
+
+My Bills
+Add New Bill
+
+
+
+
+ | Due Date |
+ Amount |
+ Description |
+ Status |
+ Actions |
+
+
+
+
+
+ | dueDate); ?> |
+ amount); ?> |
+ description); ?> |
+ isPaid ? 'Paid' : 'Pending'; ?> |
+
+ Edit
+ Delete
+ |
+
+
+
+
+
+
+
diff --git a/views/home.php b/views/home.php
new file mode 100644
index 0000000..72d7ded
--- /dev/null
+++ b/views/home.php
@@ -0,0 +1,30 @@
+
+
+Welcome to Bill Reminder
+Manage your bills efficiently and never miss a payment.
+
+
+ Hello, !
+ Go to Dashboard
+ Logout
+
+ Login
+ Register
+
+
+
\ No newline at end of file
diff --git a/views/login.php b/views/login.php
new file mode 100644
index 0000000..e0c232e
--- /dev/null
+++ b/views/login.php
@@ -0,0 +1,35 @@
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
diff --git a/views/register.php b/views/register.php
new file mode 100644
index 0000000..53951e5
--- /dev/null
+++ b/views/register.php
@@ -0,0 +1,35 @@
+
+
+
+
+
+ Register
+
+
+
+
+
+
+
+