parent
e27622f0a1
commit
8542c7fcfd
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Config;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class DisplayController extends CommonController
|
||||
{
|
||||
public function dashboard(OtherController $statistics)
|
||||
{
|
||||
$data = $statistics->homeV2Data();
|
||||
$coverage = json_decode(Config::where('key', 'threeCoverageItems')->orderBy('id', 'desc')->value('value') ?? '[]', true);
|
||||
|
||||
return $this->success([
|
||||
'list' => Arr::only($data['list'], [
|
||||
'schoolmate_total', 'schoolmate_year', 'course_signs_pass',
|
||||
'course_signs_pass_unique', 'genban_total', 'company_invested_total',
|
||||
]),
|
||||
'suzhou' => collect($data['suzhou'])->map(fn ($area) => Arr::only($area, ['area', 'total', 'total_unique'])),
|
||||
'country' => collect($data['country'])->map(fn ($area) => Arr::only($area, ['area', 'total'])),
|
||||
'monthCourses' => collect($data['monthCourses'])->map(fn ($item) => [
|
||||
'name' => data_get($item, 'title') ?: data_get($item, 'course.name', ''),
|
||||
'location' => data_get($item, 'address') ?: data_get($item, 'course.address_detail', ''),
|
||||
'teacher' => collect(data_get($item, 'course.teacher_detail'))->pluck('name')->filter()->implode('、'),
|
||||
]),
|
||||
'yearConfigs' => collect($data['yearConfigs'])->map(fn ($year) => [
|
||||
'name' => data_get($year, 'name'),
|
||||
'course_periods_total' => data_get($year, 'course_periods_total'),
|
||||
'course_signs_unique_total' => data_get($year, 'course_signs_unique_total'),
|
||||
'courseTypes' => collect(data_get($year, 'courseTypes'))->map(fn ($type) => [
|
||||
'name' => data_get($type, 'name'),
|
||||
'course_periods_total' => data_get($type, 'course_periods_total'),
|
||||
'course_signs_total' => data_get($type, 'course_signs_total'),
|
||||
])->values(),
|
||||
])->values(),
|
||||
'coverage' => collect(is_array($coverage) ? $coverage : [])
|
||||
->filter(fn ($item) => is_array($item))
|
||||
->map(fn ($item) => Arr::only($item, ['name', 'total', 'complete', 'unit']))
|
||||
->values(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admins', function (Blueprint $table) {
|
||||
$table->boolean('is_display_account')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('admins', function (Blueprint $table) {
|
||||
$table->dropColumn('is_display_account');
|
||||
});
|
||||
}
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Admin;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DisplayDashboardAccessTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
config([
|
||||
'app.key' => 'base64:' . base64_encode(str_repeat('a', 32)),
|
||||
'database.default' => 'sqlite',
|
||||
'database.connections.sqlite.database' => ':memory:',
|
||||
'cache.default' => 'array',
|
||||
'session.driver' => 'array',
|
||||
'audit.enabled' => false,
|
||||
]);
|
||||
DB::purge('sqlite');
|
||||
app('migration.repository')->createRepository();
|
||||
$migrations = [
|
||||
'2019_12_14_000001_create_personal_access_tokens_table.php',
|
||||
'2022_03_30_173108_create_permission_tables.php',
|
||||
'2022_03_30_175453_create_admins_table.php',
|
||||
'2022_04_06_102925_add_api_prefix_to_permissions.php',
|
||||
'2022_08_18_105251_create_operate_logs_table.php',
|
||||
'2024_07_17_135941_create_configs_table.php',
|
||||
'2026_11_11_000001_add_display_account_to_admins.php',
|
||||
];
|
||||
app('migrator')->run(array_map(fn ($file) => database_path('migrations/' . $file), $migrations));
|
||||
|
||||
Cache::put('home_v2_data', [
|
||||
'list' => ['schoolmate_total' => 42, 'internal_count' => 100],
|
||||
'suzhou' => [],
|
||||
'country' => [],
|
||||
'monthCourses' => [[
|
||||
'title' => '研修班',
|
||||
'course' => ['teacher_detail' => [['name' => '带班老师', 'mobile' => '123456']]],
|
||||
]],
|
||||
'yearConfigs' => [],
|
||||
'article' => ['internal_article'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_display_login_issues_a_read_only_cookie_and_logout_revokes_it(): void
|
||||
{
|
||||
$admin = Admin::create([
|
||||
'username' => 'tv',
|
||||
'name' => '电视驾驶舱',
|
||||
'password' => Hash::make('long-test-password'),
|
||||
'is_display_account' => true,
|
||||
]);
|
||||
|
||||
$login = $this->withServerVariables(['REMOTE_ADDR' => '127.0.0.1'])
|
||||
->postJson('/api/admin/auth/login', ['username' => 'tv', 'password' => 'long-test-password']);
|
||||
$login->assertExactJson(['display_only' => true]);
|
||||
$cookie = $login->getCookie(Admin::DISPLAY_COOKIE, false);
|
||||
$this->assertTrue($cookie->isHttpOnly());
|
||||
$this->assertTrue($cookie->isSecure());
|
||||
$this->assertSame('strict', $cookie->getSameSite());
|
||||
$this->assertStringNotContainsString('long-test-password', DB::table('operate_logs')->value('req_parameter'));
|
||||
|
||||
$this->withUnencryptedCookie(Admin::DISPLAY_COOKIE, $cookie->getValue())->withCredentials();
|
||||
$this->postJson('/api/admin/auth/me')->assertExactJson(['display_only' => true]);
|
||||
$this->getJson('/api/admin/display/dashboard')
|
||||
->assertJsonPath('list.schoolmate_total', 42)
|
||||
->assertJsonPath('monthCourses.0.teacher', '带班老师')
|
||||
->assertJsonMissingPath('list.internal_count')
|
||||
->assertJsonMissingPath('monthCourses.0.course')
|
||||
->assertJsonMissingPath('article')
|
||||
->assertHeader('Cache-Control', 'no-store, private');
|
||||
$this->getJson('/api/admin/configs/index')->assertJsonPath('errcode', 40001);
|
||||
$this->getJson('/api/admin/other/courses-home-export')->assertJsonPath('errcode', 40001);
|
||||
$this->postJson('/api/admin/auth-node/save', [])->assertJsonPath('errcode', 40001);
|
||||
|
||||
$this->travel(Admin::DISPLAY_SESSION_MINUTES + 1)->minutes();
|
||||
$this->getJson('/api/admin/display/dashboard')->assertJsonPath('errcode', 40001);
|
||||
$this->travelBack();
|
||||
|
||||
$this->postJson('/api/admin/auth/logout')->assertCookieExpired(Admin::DISPLAY_COOKIE);
|
||||
$this->assertSame(0, $admin->tokens()->count());
|
||||
$this->getJson('/api/admin/display/dashboard')->assertJsonPath('errcode', 40001);
|
||||
}
|
||||
|
||||
public function test_legacy_statistics_require_admin_auth_and_display_rejects_bearer_tokens(): void
|
||||
{
|
||||
foreach (['home', 'home-v2', 'courses-home-export'] as $path) {
|
||||
$this->getJson('/api/admin/other/' . $path)->assertJsonPath('errcode', 40001);
|
||||
}
|
||||
|
||||
$admin = Admin::create(['name' => '后台用户']);
|
||||
$token = $admin->createToken('token')->plainTextToken;
|
||||
$this->withToken($token)->getJson('/api/admin/other/home-v2')->assertJsonPath('list.schoolmate_total', 42);
|
||||
$this->withToken($token)->getJson('/api/admin/display/dashboard')->assertJsonPath('errcode', 40003);
|
||||
|
||||
$display = Admin::create(['name' => '大屏用户', 'is_display_account' => true]);
|
||||
$scopedToken = $display->createToken('dashboard', [Admin::DISPLAY_ABILITY])->plainTextToken;
|
||||
$this->withToken($scopedToken)->postJson('/api/admin/admin/save', [])->assertJsonPath('errcode', 40003);
|
||||
$this->withToken($scopedToken)->getJson('/api/admin/display/dashboard')->assertJsonPath('errcode', 40001);
|
||||
}
|
||||
|
||||
public function test_only_user_managers_can_create_display_accounts(): void
|
||||
{
|
||||
$manager = Admin::create(['name' => '用户管理员']);
|
||||
$token = $manager->createToken('token')->plainTextToken;
|
||||
$payload = [
|
||||
'name' => '大厅电视',
|
||||
'username' => 'lobby-tv',
|
||||
'password' => 'long-test-password',
|
||||
'is_display_account' => true,
|
||||
];
|
||||
|
||||
$this->withToken($token)->postJson('/api/admin/admin/save', $payload)->assertJsonPath('errcode', 40003);
|
||||
$permission = Permission::create(['name' => '用户管理', 'guard_name' => 'admin']);
|
||||
DB::table('permissions')->where('id', $permission->id)->update(['api_prefix' => 'api/admin/admin']);
|
||||
$manager->givePermissionTo($permission);
|
||||
$this->withToken($token)->postJson('/api/admin/admin/save', $payload)->assertJsonPath('is_display_account', true);
|
||||
$display = Admin::where('username', 'lobby-tv')->firstOrFail();
|
||||
$this->assertTrue($display->isDisplayOnly());
|
||||
$this->assertTrue(Hash::check($payload['password'], $display->password));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue