diff --git a/src/Ushahidi/Modules/V5/Actions/Post/Commands/UpdatePostCommand.php b/src/Ushahidi/Modules/V5/Actions/Post/Commands/UpdatePostCommand.php index 42e2e7c8cb..601c06cdf5 100644 --- a/src/Ushahidi/Modules/V5/Actions/Post/Commands/UpdatePostCommand.php +++ b/src/Ushahidi/Modules/V5/Actions/Post/Commands/UpdatePostCommand.php @@ -58,19 +58,11 @@ public static function fromRequest(int $id, PostRequest $request, Post $current_ // dd($request->input()); $user = Auth::user(); - if (self::hasPermissionToUpdateUser($user)) { - $input['user_id'] = $request->has('user_id') - ? $request->input('user_id') : $current_post->user_id; - ; - } else { - $input['user_id'] = $current_post->user_id; - } + $input['user_id'] = $user->id; + $input['author_realname'] = $user->realname; + $input['author_email'] = $user->email; $input['slug'] = $request->input('slug') ? Post::makeSlug($request->input('slug')) : $current_post->slug; - $input['author_email'] = $request->has('author_email') - ? $request->input('author_email') : $current_post->author_email; - $input['author_realname'] = $request->has('author_realname') - ? $request->input('author_realname') : $current_post->author_realname; $input['form_id'] = $request->has('form_id') ? $request->input('form_id') : $current_post->form_id; $input['parent_id'] = $request->has('parent_id') diff --git a/src/Ushahidi/Modules/V5/DTO/PostSearchFields.php b/src/Ushahidi/Modules/V5/DTO/PostSearchFields.php index 90c1804cca..0e3b2e898a 100644 --- a/src/Ushahidi/Modules/V5/DTO/PostSearchFields.php +++ b/src/Ushahidi/Modules/V5/DTO/PostSearchFields.php @@ -44,6 +44,8 @@ class PostSearchFields extends SearchFields protected $center_point; protected $include_unstructured_posts; + protected $role; + // before ready protected $set; @@ -161,6 +163,12 @@ public function __construct(Request $request) $this->set = $this->getParameterAsArray($request->get('set')); $this->tags = $this->getParameterAsArray($request->get('tags')); + + if (Auth::user()) { + $this->role = Auth::user()->role; + } else { + $this->role = null; + } } @@ -315,4 +323,14 @@ public function includeUnstructuredPosts() { return $this->include_unstructured_posts; } + + public function role(): ?string + { + return $this->role; + } + + public function isAdmin(): bool + { + return $this->role === 'admin'; + } } diff --git a/src/Ushahidi/Modules/V5/DTO/SurveySearchFields.php b/src/Ushahidi/Modules/V5/DTO/SurveySearchFields.php index 2e0fdf1f83..3cb61a0b80 100644 --- a/src/Ushahidi/Modules/V5/DTO/SurveySearchFields.php +++ b/src/Ushahidi/Modules/V5/DTO/SurveySearchFields.php @@ -3,6 +3,7 @@ namespace Ushahidi\Modules\V5\DTO; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class SurveySearchFields extends SearchFields { @@ -12,15 +13,31 @@ class SurveySearchFields extends SearchFields protected $query; public $showUnknownForm; + private $role; public function __construct(Request $request) { $this->query = $request->query('q'); $this->showUnknownForm = $request->query('show_unknown_form', false); + if (Auth::user()) { + $this->role = Auth::user()->role; + } else { + $this->role = null; + } } public function q(): ?string { return $this->query; } + + public function role(): ?string + { + return $this->role; + } + + public function isAdmin(): bool + { + return $this->role === 'admin'; + } } diff --git a/src/Ushahidi/Modules/V5/Http/Controllers/PostController.php b/src/Ushahidi/Modules/V5/Http/Controllers/PostController.php index a00de20a20..8cdb2c43a0 100644 --- a/src/Ushahidi/Modules/V5/Http/Controllers/PostController.php +++ b/src/Ushahidi/Modules/V5/Http/Controllers/PostController.php @@ -67,6 +67,162 @@ protected function ignoreInput() return ['author_email', 'slug', 'user_id', 'author_realname', 'created', 'updated']; } + public function unread(Request $request) + { + $refreshed_at = $request->query('refreshed_at'); + $now = time(); + + if (!$refreshed_at || !is_numeric($refreshed_at) || (int)$refreshed_at >= $now) { + $refreshed_at = $now; + } + + $results = DB::select("SELECT COUNT(*) AS count from posts WHERE created > ?", [$refreshed_at]); + $count = $results[0]->count ?? 0; + + return response()->json(['count' => $count]); + } + + public function move(Request $request) + { + $authorizer = service('authorizer.form'); + $user = $authorizer->getUser(); + $role = $user->role; + + if (!in_array($role, ['admin', 'user'], true)) { + return response()->json(['error' => 'Unauthorized'], 403); + } + + $post_id = (int) $request->query('post_id'); + $form_id = (int) $request->query('form_id'); + + if (!$post_id || !$form_id) { + return response()->json(['error' => 'Missing post_id or form_id'], 422); + } + + DB::beginTransaction(); + try { + // Step 1: Fetch current post data + $post_rows = DB::select( + "SELECT form_id as old_form_id, content FROM ushahidi.posts WHERE id = ?", + [$post_id] + ); + + if (empty($post_rows)) { + DB::rollback(); + return response()->json(['error' => 'Post not found'], 404); + } + + $old_form_id = $post_rows[0]->old_form_id; + $content = $post_rows[0]->content ?? ''; + + // Fetch old and new form names + $old_form_rows = DB::select( + "SELECT name FROM ushahidi.forms WHERE id = ?", + [$old_form_id] + ); + $form_name = $old_form_rows[0]->name ?? $old_form_id; + + $new_form_rows = DB::select( + "SELECT name FROM ushahidi.forms WHERE id = ?", + [$form_id] + ); + $new_form_name = $new_form_rows[0]->name ?? $form_id; + + // Append migration note to content + $content .= "\n\n--- Survey moved from [{$form_name}] to [{$new_form_name}] ---\n\n"; + + // Step 2: Fetch old form attributes + $old_attributes = DB::select( + "SELECT A.id, A.label, A.input, A.type, A.options + FROM ushahidi.form_attributes A + JOIN ushahidi.form_stages B ON (A.form_stage_id = B.id) + WHERE B.form_id = ?", + [$old_form_id] + ); + + // Fetch new form attributes + $new_attributes = DB::select( + "SELECT A.id, A.label, A.input, A.type, A.options + FROM ushahidi.form_attributes A + JOIN ushahidi.form_stages B ON (A.form_stage_id = B.id) + WHERE B.form_id = ?", + [$form_id] + ); + + // Step 3: Process each old attribute (skip title and description types) + foreach ($old_attributes as $old_attr) { + $id = $old_attr->id; + $label = $old_attr->label; + $input = $old_attr->input; + $type = $old_attr->type; + $options = $old_attr->options; + + if (in_array($type, ['title', 'description', 'tags'], true)) { + continue; + } + + // Look for a matching attribute in the new form + $matched_new = null; + foreach ($new_attributes as $new_attr) { + if ( + $new_attr->label === $label && + $new_attr->input === $input && + $new_attr->type === $type && + $new_attr->options === $options + ) { + $matched_new = $new_attr; + break; + } + } + + if ($matched_new !== null) { + // Matching attribute found — reassign the post value to the new attribute id + $new_id = $matched_new->id; + DB::statement( + "UPDATE ushahidi.post_{$type} + SET form_attribute_id = ? + WHERE post_id = ? AND form_attribute_id = ?", + [$new_id, $post_id, $id] + ); + } else { + // No match — retrieve current value, delete the row, and log it in content + $value_rows = DB::select( + "SELECT value FROM ushahidi.post_{$type} + WHERE post_id = ? AND form_attribute_id = ?", + [$post_id, $id] + ); + $value = $value_rows[0]->value ?? ''; + + DB::statement( + "DELETE FROM ushahidi.post_{$type} + WHERE post_id = ? AND form_attribute_id = ?", + [$post_id, $id] + ); + + $content .= "{$label} -> {$value}\n"; + } + } + + // Step 4: Update the post with the new form_id and updated content + DB::statement( + "UPDATE ushahidi.posts SET form_id = ?, content = ? WHERE id = ?", + [$form_id, $content, $post_id] + ); + + DB::commit(); + + return response()->json([ + 'status' => 'completed', + 'post_id' => $post_id, + 'form_id' => $form_id, + ], 200); + + } catch (\Exception $e) { + DB::rollback(); + return response()->json(['error' => $e->getMessage()], 500); + } + } + /** * Display the specified resource. * diff --git a/src/Ushahidi/Modules/V5/Repository/Post/EloquentPostRepository.php b/src/Ushahidi/Modules/V5/Repository/Post/EloquentPostRepository.php index 6bba6d2ece..c340aa139e 100644 --- a/src/Ushahidi/Modules/V5/Repository/Post/EloquentPostRepository.php +++ b/src/Ushahidi/Modules/V5/Repository/Post/EloquentPostRepository.php @@ -340,20 +340,30 @@ public function paginate( array $with = [] ): LengthAwarePaginator { $fields = $this->addPostsTableNamePrefix($fields); - // add the order field if not found - if (!in_array('posts.'.$paging->getOrderBy(), $fields)) { - $fields[] = 'posts.'.$paging->getOrderBy(); + $orderBy = $paging->getOrderBy(); + + $query = Post::query(); + + if ($orderBy === 'event_date') { + $query->select($fields) + ->selectRaw('COALESCE((SELECT MAX(value) FROM post_datetime WHERE post_id = posts.id), posts.post_date) as event_date') + ->orderBy('event_date', $paging->getOrder()); + } else { + // add the order field if not found + if (!in_array('posts.'.$orderBy, $fields)) { + $fields[] = 'posts.'.$orderBy; + } + $query->orderBy('posts.'.$orderBy, $paging->getOrder()); + + if (count($fields)) { + $query->select($fields); + } } - $query = Post::take($paging->getLimit()) - //->skip($paging->getSkip()) - ->orderBy('posts.'.$paging->getOrderBy(), $paging->getOrder()); + $query->take($paging->getLimit()); $query = $this->setSearchCondition($search_fields, $query); $query = $this->setGuestConditions($query); - if (count($fields)) { - $query->select($fields); - } if (count($with)) { $query->with($with); } diff --git a/src/Ushahidi/Modules/V5/Repository/Survey/EloquentSurveyRepository.php b/src/Ushahidi/Modules/V5/Repository/Survey/EloquentSurveyRepository.php index 0a0d7cb8e9..82b6318471 100644 --- a/src/Ushahidi/Modules/V5/Repository/Survey/EloquentSurveyRepository.php +++ b/src/Ushahidi/Modules/V5/Repository/Survey/EloquentSurveyRepository.php @@ -134,6 +134,27 @@ private function setSearchCondition(SurveySearchFields $survey_search_fields, $b $builder->where('name', 'LIKE', "%" . $survey_search_fields->q() . "%"); } + if (!$survey_search_fields->isAdmin()) { + $role = $survey_search_fields->role(); + $builder->where(function (Builder $query) use ($role) { + $query->whereNotExists(function ($subquery) { + $subquery->select(DB::raw(1)) + ->from('form_roles') + ->whereColumn('form_roles.form_id', 'forms.id'); + }); + + if ($role) { + $query->orWhereExists(function ($subquery) use ($role) { + $subquery->select(DB::raw(1)) + ->from('form_roles') + ->join('roles', 'roles.id', '=', 'form_roles.role_id') + ->whereColumn('form_roles.form_id', 'forms.id') + ->where('roles.name', '=', $role); + }); + } + }); + } + return $builder; } diff --git a/src/Ushahidi/Modules/V5/routes/api.php b/src/Ushahidi/Modules/V5/routes/api.php index 71d5689c70..4d7f39cb99 100644 --- a/src/Ushahidi/Modules/V5/routes/api.php +++ b/src/Ushahidi/Modules/V5/routes/api.php @@ -105,6 +105,8 @@ function () use ($router) { $router->get('/', 'PostController@index'); $router->get('/stats', 'PostController@stats'); + $router->get('/unread', 'PostController@unread'); + $router->get('/move', 'PostController@move'); $router->get('/geojson', 'PostController@indexGeoJson'); $router->get('/geojson/{zoom}/{x}/{y}', 'PostController@indexGeoJsonWithZoom'); $router->get('/{id}', 'PostController@show');