This commit is contained in:
2026-08-20 18:09:11 +03:30
parent b2da21e99c
commit ff946959a5
4 changed files with 128 additions and 7 deletions
+69
View File
@@ -0,0 +1,69 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
class SyncSurveyUsers extends Command
{
protected $signature = 'survey:sync-users {--token= : Approagency admin token}';
protected $description = 'Sync user profile fields (name, age, gender) from approagency for all meditation users with missing data';
public function handle()
{
$token = $this->option('token') ?: config('services.approagency.token');
if (empty($token)) {
$this->error('Provide --token=<approagency_admin_token> or set APPROAGENCY_ADMIN_TOKEN in .env');
return 1;
}
$users = User::whereNull('first_name')
->whereNotNull('mobile')
->get();
$this->info("Found {$users->count()} users with missing first_name. Syncing...");
$synced = 0;
$failed = 0;
foreach ($users as $user) {
try {
$response = Http::withToken($token)
->get('https://api.approagency.ir/api/admin/users', [
'mobile' => $user->mobile,
'per_page' => 1,
]);
if ($response->successful()) {
$data = $response->json('data.0');
if ($data) {
$user->update([
'first_name' => $data['first_name'] ?? $user->first_name,
'last_name' => $data['last_name'] ?? $user->last_name,
'age' => $data['age'] ?? $user->age,
'gender' => $data['gender'] ?? $user->gender,
'birthday' => $data['birthday'] ?? $user->birthday,
'identifier' => $data['uuid'] ?? $user->identifier,
]);
$this->line(" synced: {$user->mobile}{$data['first_name'] ?? 'null'}");
$synced++;
}
} else {
$this->warn(" skip: {$user->mobile} (HTTP {$response->status()})");
$failed++;
}
} catch (\Exception $e) {
$this->error(" failed: {$user->mobile}{$e->getMessage()}");
$failed++;
}
usleep(200000); // 200ms delay to avoid rate limits
}
$this->info("Done. Synced: {$synced}, Failed: {$failed}");
return 0;
}
}
@@ -9,6 +9,7 @@
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;
class SurveyQuestionController extends Controller
@@ -127,6 +128,34 @@ public function adminUserShow($identifier)
return response()->json($user);
}
// ADMIN: update a user's profile fields from approagency data.
public function adminUserUpdate(Request $request, $identifier)
{
if (is_numeric($identifier)) {
$user = User::where('id', $identifier)->first();
} else {
$user = User::where('identifier', $identifier)->first();
}
if (!$user) {
abort(404);
}
$data = $request->validate([
'first_name' => 'nullable|string',
'last_name' => 'nullable|string',
'age' => 'nullable|integer',
'gender' => 'nullable|integer',
'birthday' => 'nullable|string',
'identifier' => 'nullable|string',
'email' => 'nullable|email',
]);
$user->update(array_filter($data, fn ($v) => !is_null($v)));
return response()->json($user);
}
// ADMIN: clean aggregated results — per option vote counts & percentages, no raw rows.
// Pass an $id for one question, omit it for all questions.
public function adminAnalytics($id = null)
+29 -7
View File
@@ -66,21 +66,31 @@ public function loginV2(Request $request)
'email' => $response['email'],
'identifier' => $response['uuid'] ?? null,
'password' => config('app.default_password'),
// 'name' => trim(($response['first_name'] ?? '') . ' ' . ($response['last_name'] ?? '')),
'mobile' => $mobile,
'first_name' => $response['first_name'] ?? null,
'last_name' => $response['last_name'] ?? null,
'age' => $response['age'] ?? null,
'gender' => $response['gender'] ?? null,
'birthday' => $response['birthday'] ?? null,
'referral_code' => $response['referral_code'] ?? null,
]);
} else {
// Only update name and mobile for existing user
// Keep the local identifier aligned with the current approagency uuid
// (e.g. when the user was matched by mobile, not identifier).
$user->identifier = $response['uuid'] ?? $user->identifier;
$user->first_name = $response['first_name'] ?? $user->first_name;
$user->last_name = $response['last_name'] ?? $user->last_name;
// $user->name = trim(($response['first_name'] ?? '') . ' ' . ($response['last_name'] ?? ''));
// Sync names — update if the response has a non-null, non-empty value
if (!empty($response['first_name'])) {
$user->first_name = $response['first_name'];
}
if (!empty($response['last_name'])) {
$user->last_name = $response['last_name'];
}
$user->mobile = $mobile ?? $user->mobile;
$user->age = $response['age'] ?? $user->age;
$user->gender = $response['gender'] ?? $user->gender;
$user->birthday = $response['birthday'] ?? $user->birthday;
$user->referral_code = $response['referral_code'] ?? $user->referral_code;
$user->save();
}
@@ -134,15 +144,27 @@ private function syncUserFromStatus(array $response, ?User $user = null): User
'mobile' => $mobile,
'first_name' => $response['first_name'] ?? null,
'last_name' => $response['last_name'] ?? null,
'age' => $response['age'] ?? null,
'gender' => $response['gender'] ?? null,
'birthday' => $response['birthday'] ?? null,
'referral_code' => $response['referral_code'] ?? null,
'email_verified_at' => $response['email_verified_at'] ?? null
]);
} else {
// update existing
$user->identifier = $response['uuid'] ?? $user->identifier;
$user->first_name = $response['first_name'] ?? $user->first_name;
$user->last_name = $response['last_name'] ?? $user->last_name;
if (!empty($response['first_name'])) {
$user->first_name = $response['first_name'];
}
if (!empty($response['last_name'])) {
$user->last_name = $response['last_name'];
}
$user->mobile = $mobile ?? $user->mobile;
$user->age = $response['age'] ?? $user->age;
$user->gender = $response['gender'] ?? $user->gender;
$user->birthday = $response['birthday'] ?? $user->birthday;
$user->referral_code = $response['referral_code'] ?? $user->referral_code;
$user->email_verified_at = $response['email_verified_at'] ?? $user->email_verified_at;
$user->save();
+1
View File
@@ -169,6 +169,7 @@
// User list + detail for survey admin
Route::get('/admin/survey-users', [SurveyQuestionController::class, 'adminUsers']);
Route::get('/admin/survey-users/{id}', [SurveyQuestionController::class, 'adminUserShow']);
Route::patch('/admin/survey-users/{id}', [SurveyQuestionController::class, 'adminUserUpdate']);
});
// User: answer + read questions with their own answers only.
Route::get('/survey-questions/suggested-media', [SurveyQuestionController::class, 'suggestedMedia']);