diff --git a/apps/Admin/Controllers/AdminDeleteController.php b/apps/Admin/Controllers/AdminDeleteController.php index 17ac960..4458d61 100644 --- a/apps/Admin/Controllers/AdminDeleteController.php +++ b/apps/Admin/Controllers/AdminDeleteController.php @@ -50,6 +50,12 @@ class AdminDeleteController extends Abstract\AdminBaseController 'field_display' => 'ingredient_name', 'back_to' => 'admin:ing-cat-rel', ], + [ + 'url_name' => 'recipe-reviews', + 'model' => 'Lycoreco\Apps\Recipes\Models\ReviewsModel', + 'field_display' => 'field_title', + 'back_to' => 'admin:review', + ], ]; protected $template_name = APPS_PATH . '/Admin/Templates/delete.php'; diff --git a/apps/Admin/Controllers/AdminReviewControler.php b/apps/Admin/Controllers/AdminReviewControler.php new file mode 100644 index 0000000..debce04 --- /dev/null +++ b/apps/Admin/Controllers/AdminReviewControler.php @@ -0,0 +1,44 @@ + 'title', + 'input_type' => 'text', + 'input_attrs' => ['required'] + ], + [ + 'model_field' => 'rating', + 'input_type' => 'number', + 'input_attrs' => ['required'] + ], + [ + 'model_field' => 'content', + 'input_type' => 'textarea', + 'input_attrs' => ['required'] + ], + [ + 'model_field' => 'status', + 'input_type' => 'select', + 'input_attrs' => ['required'], + 'input_values' => ReviewsModel::STATUS + ], + [ + 'model_field' => 'created_at', + 'input_type' => 'text', + 'dynamic_save' => false, + 'input_label' => 'Created at', + 'input_attrs' => ['disabled'] + ] + ); +} \ No newline at end of file diff --git a/apps/Admin/Controllers/AdminReviewListController.php b/apps/Admin/Controllers/AdminReviewListController.php new file mode 100644 index 0000000..c531ed5 --- /dev/null +++ b/apps/Admin/Controllers/AdminReviewListController.php @@ -0,0 +1,17 @@ + 'field_title', + 'Rating' => 'field_rating', + 'Status ' => 'get_status()', + 'Creaated at' => 'field_created_at', + ); + protected $single_router_name = 'admin:review'; + protected $verbose_name = "review"; + protected $verbose_name_multiply = "reviews"; +} \ No newline at end of file diff --git a/apps/Admin/Templates/components/admin-header.php b/apps/Admin/Templates/components/admin-header.php index de94a83..8ac60d3 100644 --- a/apps/Admin/Templates/components/admin-header.php +++ b/apps/Admin/Templates/components/admin-header.php @@ -26,6 +26,11 @@ $sidebar_links = [ 'name' => 'Ingredients', 'icon' => 'fa-solid fa-carrot', 'router_name' => 'admin:ingredient-list' + ], + [ + 'name' => 'Reviews', + 'icon' => 'fa-solid fa-comment', + 'router_name' => 'admin:review-list' ] ]; ?> diff --git a/apps/Admin/urls.php b/apps/Admin/urls.php index 22e813f..ddc6efa 100644 --- a/apps/Admin/urls.php +++ b/apps/Admin/urls.php @@ -12,6 +12,7 @@ $admin_urls = [ new Path('/admin/recipes',new Controllers\AdminRecipeListController(), 'recipe-list'), new Path('/admin/categories',new Controllers\AdminCategoryListController(), 'category-list'), new Path('/admin/ingredients',new Controllers\IngredientListController(), 'ingredient-list'), + new Path('/admin/reviews', new Controllers\AdminReviewListController(), 'review-list'), ////// Single object /////// // User @@ -35,6 +36,9 @@ $admin_urls = [ new Path('/admin/ingredient/[:int]', new Controllers\IngredientController(), 'ingredient'), new Path('/admin/ingredient/new', new Controllers\IngredientController(true), 'ingredient-new'), + // Reviews + new Path('/admin/review/[:int]', new Controllers\AdminReviewControler(), 'review'), + // Recipe ingedient relation new Path('/admin/recipe/[:int]/ingredients', new Controllers\IngredientRecipeRelListController(), 'ing-cat-rel-list'), new Path('/admin/recipe/ingredient/[:int]', new Controllers\IngredientRecipeRelController(), 'ing-cat-rel'), diff --git a/apps/Index/Controllers/HomepageController.php b/apps/Index/Controllers/HomepageController.php index eb9111d..fbe7d17 100644 --- a/apps/Index/Controllers/HomepageController.php +++ b/apps/Index/Controllers/HomepageController.php @@ -5,6 +5,7 @@ namespace Lycoreco\Apps\Index\Controllers; use Lycoreco\Apps\Recipes\Models\CategoryModel; use Lycoreco\Apps\Recipes\Models\RecipeModel; use Lycoreco\Apps\Recipes\Models\RecipeUserMenu; +use Lycoreco\Apps\Recipes\Models\ReviewsModel; use Lycoreco\Includes\BaseController; require_once(INCLUDES_PATH . '/Const/recipes.php'); @@ -29,6 +30,16 @@ class HomepageController extends BaseController $dayNumber = date("w"); $dayofweek = DAYS_OF_WEEK[$dayNumber]; + $context['reviews'] = ReviewsModel::filter(array( + [ + 'name' => 'obj.status', + 'type' => '=', + 'value' => 'publish' + ]), + ['-obj.created_at'], + 6 + ); + if(CURRENT_USER) { $context['usermenu_recipe_prefetch'] = RecipeUserMenu::get_prefetch_recipes(CURRENT_USER, $dayofweek); } diff --git a/apps/Index/Templates/index.php b/apps/Index/Templates/index.php index 9c03da4..c4e3197 100644 --- a/apps/Index/Templates/index.php +++ b/apps/Index/Templates/index.php @@ -86,104 +86,23 @@ the_header(

Recent User Reviews

- + +
- reviewed recipe + reviewed recipe
-

Just Like Mom's

+

recipe_title ?>

-

I made this spaghetti last night and it was absolutely delicious! The sauce was rich and - flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili - flakes for a little kick, and it turned out perfect...

+

get_excerpt() ?>

-

GreenDavid004

-

2023-10-01

-
-
- -
-
- reviewed recipe -
-

Just Like Mom's

-
-
-

I made this spaghetti last night and it was absolutely delicious! The sauce was rich and - flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili - flakes for a little kick, and it turned out perfect...

-
-
-

GreenDavid004

-

2023-10-01

-
-
-
-
- reviewed recipe -
-

Just Like Mom's

-
-
-

I made this spaghetti last night and it was absolutely delicious! The sauce was rich and - flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili - flakes for a little kick, and it turned out perfect...

-
-
-

GreenDavid004

-

2023-10-01

-
-
-
-
- reviewed recipe -
-

Just Like Mom's

-
-
-

I made this spaghetti last night and it was absolutely delicious! The sauce was rich and - flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili - flakes for a little kick, and it turned out perfect...

-
-
-

GreenDavid004

-

2023-10-01

-
-
-
-
- reviewed recipe -
-

Just Like Mom's

-
-
-

I made this spaghetti last night and it was absolutely delicious! The sauce was rich and - flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili - flakes for a little kick, and it turned out perfect...

-
-
-

GreenDavid004

-

2023-10-01

-
-
-
-
- reviewed recipe -
-

Just Like Mom's

-
-
-

I made this spaghetti last night and it was absolutely delicious! The sauce was rich and - flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili - flakes for a little kick, and it turned out perfect...

-
-
-

GreenDavid004

-

2023-10-01

+

author_username ?>

+

get_date() ?>

+
diff --git a/apps/Recipes/Controllers/SingleRecipeController.php b/apps/Recipes/Controllers/SingleRecipeController.php index e50a99e..0ba4ebe 100644 --- a/apps/Recipes/Controllers/SingleRecipeController.php +++ b/apps/Recipes/Controllers/SingleRecipeController.php @@ -2,16 +2,51 @@ namespace Lycoreco\Apps\Recipes\Controllers; +use Exception; use Lycoreco\Apps\Recipes\Models\IngredientInRecipeModel; use Lycoreco\Apps\Recipes\Models\RecipeModel; +use Lycoreco\Apps\Recipes\Models\ReviewsModel; use Lycoreco\Apps\Users\Models\UserModel; use Lycoreco\Includes\BaseController; +use Lycoreco\Includes\Model\ValidationError; use Lycoreco\Includes\Routing\HttpExceptions; class SingleRecipeController extends BaseController { protected $template_name = APPS_PATH . '/Recipes/Templates/single.php'; + protected function post() + { + if(!CURRENT_USER) { + $this->context['reviews_error'] = 'You are not authorized'; + return; + } + $rating = $_POST['rating-select'] ?? null; + $title = $_POST['review-title'] ?? null; + $content = $_POST['review-body-input'] ?? null; + + $recipe = $this->get_model(); + + $review = new ReviewsModel(); + $review->field_title = $title; + $review->field_content = $content; + $review->field_rating = $rating; + $review->field_status = 'pending'; + $review->field_user_id = CURRENT_USER->get_id(); + $review->field_recipe_id = $recipe->get_id(); + + try { + $review->save(); + $this->context['display_review_form'] = false; + } + catch(ValidationError $ex) { + $this->context['reviews_error'] = $ex->getMessage(); + } + catch(Exception $ex) { + $this->context['reviews_error'] = 'Unexpected error'; + } + } + protected function get_model() { if (isset($this->__model)) @@ -39,6 +74,7 @@ class SingleRecipeController extends BaseController $context['recipe'] = $recipe; + $context['display_review_form'] = true; $context['author'] = UserModel::get(array( [ @@ -56,6 +92,42 @@ class SingleRecipeController extends BaseController ] )); + $context['reviews'] = ReviewsModel::filter(array( + [ + 'name' => 'obj.recipe_id', + 'type' => '=', + 'value' => $recipe->get_id() + ], + [ + 'name' => 'obj.status', + 'type' => '=', + 'value' => 'publish' + ], + )); + $context['reviews_average'] = '0.0'; + if(!empty($context['reviews'])) { + $sum = array_sum(array_column($context['reviews'], 'field_rating')); + $count = count($context['reviews']); + $context['reviews_average'] = number_format($sum / $count, 1); + } + + if(CURRENT_USER) { + $review_exists = ReviewsModel::count(array( + [ + 'name' => 'obj.recipe_id', + 'type' => '=', + 'value' => $recipe->get_id() + ], + [ + 'name' => 'obj.user_id', + 'type' => '=', + 'value' => CURRENT_USER->get_id() + ] + )); + if($review_exists > 0) + $context['display_review_form'] = false; + } + return $context; } } diff --git a/apps/Recipes/Models/ReviewsModel.php b/apps/Recipes/Models/ReviewsModel.php new file mode 100644 index 0000000..2ef4c69 --- /dev/null +++ b/apps/Recipes/Models/ReviewsModel.php @@ -0,0 +1,121 @@ + 'int', + 'title' => 'string', + 'content' => 'string', + 'rating' => 'int', + 'status' => 'string', + + 'recipe_id' => 'int', + 'user_id' => 'int', + 'created_at' => 'DateTime', + ]; + static protected $additional_fields = array( + [ + 'field' => [ + 'us.username AS author_username' + ], + 'join_table' => 'users us ON us.id = obj.user_id' + ], + [ + 'field' => [ + 're.title AS recipe_title', + 're.image_url AS recipe_image' + ], + 'join_table' => 'recipes re ON re.id = obj.recipe_id' + ] + ); + + public static function init_table() + { + $result = db_query('CREATE TABLE ' . static::$table_name . ' ( + id INT AUTO_INCREMENT PRIMARY KEY, + + title VARCHAR(255) NOT NULL, + content TEXT NOT NULL, + rating INT NOT NULL, + status VARCHAR(20) NOT NULL CHECK (status IN (\'publish\', \'pending\')), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + recipe_id INT NOT NULL, + user_id INT NOT NULL, + + FOREIGN KEY (recipe_id) REFERENCES recipes(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + );'); + return $result; + } + + public function get_html_content(): string + { + return nl2br(trim($this->field_content)); + } + public function get_status() + { + return ucfirst($this->field_status); + } + public function get_date() + { + $date = new DateTime($this->field_created_at); + return $date->format('d.m.Y'); + } + public function get_excerpt() + { + $max_length = 100; + $excerpt = mb_substr($this->field_content, 0, $max_length); + + if(mb_strlen($this->field_content) > $max_length) + $excerpt .= '...'; + + return $excerpt; + } + public function get_recipe_image() + { + $recipe = new RecipeModel(); + $recipe->field_image_url = $this->recipe_image; + return $recipe->get_image_url(); + } + public function valid() { + $errors = array(); + + if(empty($this->field_title)) + $errors[] = 'Title field is empty'; + + if(empty($this->field_content)) + $errors[] = 'Content field is empty'; + + $this->field_rating = (int)$this->field_rating; + if($this->field_rating < 1 || $this->field_rating > 5) { + $errors[] = 'Rating must be between 1 and 5'; + } + + if (empty($errors)) + return true; + + return $errors; + } +} \ No newline at end of file diff --git a/apps/Recipes/Templates/single.php b/apps/Recipes/Templates/single.php index 90395eb..1798525 100644 --- a/apps/Recipes/Templates/single.php +++ b/apps/Recipes/Templates/single.php @@ -130,45 +130,40 @@ the_header(

Reviews

-

Average Rating: 4.5

+

Average Rating:

All Reviews

+ +
Nothing to show
+ + +
- 5 Divine disc of - deliciousness! + field_rating ?>   field_title ?>
- Blessings of Aqua-sama upon you, fellow foodies! As a proud and very sane member of the Axis - Cult, I recently partook in a holy culinary experience that rivaled even the sacred waters - of the Blue Lake: a homemade pepperoni and mushroom pizza! - The moment I laid eyes on that glorious golden crust, I knew—Aqua-sama herself must have - guided my ovens temperature dial! The cheese was melted with such heavenly grace, - stretching with every bite like the ribbons of our goddesss divine garments. The pepperoni? - Spicy circles of salvation! And the mushrooms—earthy little blessings sent straight from the - soil Aqua purifies daily! - The crust had the perfect balance of crispy edge and fluffy soul. It crackled like the - laughter of a cultist pranking a stubborn Eris follower (teehee~). Each bite sang praises in - my mouth: “Axis! Axis! AXIS!!” - Would I recommend this pizza? Of course! Id even offer it as tribute at the next festival - in Aquas honor. Try it yourself and bask in the savory enlightenment. And remember: if it - tastes weird, just pour holy water on it. Or beer. Aqua would approve either way. - Rating: 5 out of 5 Axis Blessings!(Any lower would be heresy.) + get_html_content() ?>
- GreenDavid004 + author_username ?>
-
+
get_date() ?>
+
+

Your Review

+