diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index da93cf6b..29c0dfab 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -56,7 +56,7 @@ jobs: fail-fast: false matrix: php: [8.4, 8.3, 8.2] - laravel: [11.x] + laravel: [12.x, 11.x] stability: [prefer-lowest, prefer-stable] name: Static Analysis - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} @@ -112,7 +112,7 @@ jobs: fail-fast: false matrix: php: [8.4, 8.3, 8.2] - laravel: [11.x] + laravel: [12.x, 11.x] stability: [prefer-lowest, prefer-stable] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - MySQL 8.0 @@ -182,7 +182,7 @@ jobs: fail-fast: false matrix: php: [8.4, 8.3, 8.2] - laravel: [11.x] + laravel: [12.x, 11.x] stability: [prefer-lowest, prefer-stable] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - PostgreSQL 13 @@ -251,8 +251,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ 8.3, 8.2 ] - laravel: [ 11.x ] + php: [8.4, 8.3, 8.2] + laravel: [12.x, 11.x] stability: [ prefer-lowest, prefer-stable ] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - PostgreSQL 14 @@ -321,8 +321,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ 8.3, 8.2 ] - laravel: [ 11.x ] + php: [8.4, 8.3, 8.2] + laravel: [12.x, 11.x] stability: [ prefer-lowest, prefer-stable ] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - PostgreSQL 15 @@ -379,8 +379,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ 8.3, 8.2 ] - laravel: [ 11.x ] + php: [8.4, 8.3, 8.2] + laravel: [12.x, 11.x] stability: [ prefer-lowest, prefer-stable ] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - SQLite diff --git a/.phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a b/.phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a new file mode 100644 index 00000000..48652705 Binary files /dev/null and b/.phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a differ diff --git a/.phpintel/index b/.phpintel/index new file mode 100644 index 00000000..ccb53243 Binary files /dev/null and b/.phpintel/index differ diff --git a/composer.json b/composer.json index 789da0f2..301394fc 100644 --- a/composer.json +++ b/composer.json @@ -25,19 +25,19 @@ "filament/filament": "^4.0", "filament/spatie-laravel-settings-plugin": "^4.0", "guzzlehttp/guzzle": "^7.8", - "illuminate/cache": "^11.35.0", - "illuminate/console": "^11.35.0", - "illuminate/database": "^11.35.0", - "illuminate/events": "^11.35.0", - "illuminate/queue": "^11.35.0", - "illuminate/support": "^11.35.0", + "illuminate/cache": "^11.35.0|^12.0", + "illuminate/console": "^11.35.0|^12.0", + "illuminate/database": "^11.35.0|^12.0", + "illuminate/events": "^11.35.0|^12.0", + "illuminate/queue": "^11.35.0|^12.0", + "illuminate/support": "^11.35.0|^12.0", "laravel/sanctum": "^4.0", - "nesbot/carbon": "^2.70", + "nesbot/carbon": "^2.70|^3.0", "spatie/laravel-data": "^4.11", - "spatie/laravel-query-builder": "^5.5", + "spatie/laravel-query-builder": "^6.3", "spatie/laravel-settings": "^3.2", "spatie/laravel-webhook-server": "^3.8", - "timacdonald/json-api": "^1.0.0-beta.4", + "timacdonald/json-api": "^1.0.0-beta.10", "twig/twig": "^3.0" }, "require-dev": { @@ -47,11 +47,11 @@ "laravel/mcp": "^0.5", "laravel/pail": "^1.1", "laravel/pint": "^1.24", - "orchestra/testbench": "^9.15.1", + "orchestra/testbench": "^9.15.1|^10.0", "pestphp/pest": "^3.8", - "pestphp/pest-plugin-laravel": "^3.0", - "pestphp/pest-plugin-livewire": "*", - "pestphp/pest-plugin-type-coverage": "^3.3", + "pestphp/pest-plugin-laravel": "^3.7", + "pestphp/pest-plugin-livewire": "^3.0", + "pestphp/pest-plugin-type-coverage": "^3.5", "psalm/plugin-laravel": "^3.14" }, "minimum-stability": "dev", diff --git a/src/Http/Controllers/Api/IncidentController.php b/src/Http/Controllers/Api/IncidentController.php index f8be581f..6879f40b 100644 --- a/src/Http/Controllers/Api/IncidentController.php +++ b/src/Http/Controllers/Api/IncidentController.php @@ -12,7 +12,7 @@ use Cachet\Models\Incident; use Dedoc\Scramble\Attributes\Group; use Dedoc\Scramble\Attributes\QueryParameter; -use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Routing\Controller; use Spatie\QueryBuilder\AllowedFilter; @@ -38,22 +38,20 @@ class IncidentController extends Controller */ #[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)] #[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)] - public function index() + public function index(Request $request) { - $query = Incident::query() - ->when(! request('sort'), function (Builder $builder) { - $builder->orderByDesc('created_at'); - }); - - $incidents = QueryBuilder::for($query) + $incidents = QueryBuilder::for(Incident::query()) ->allowedIncludes(self::ALLOWED_INCLUDES) ->allowedFilters([ 'name', AllowedFilter::exact('status'), - 'occurred_at', + AllowedFilter::scope('occurs_after'), + AllowedFilter::scope('occurs_before'), + AllowedFilter::scope('occurs_on'), ]) - ->allowedSorts(['name', 'status', 'id']) - ->simplePaginate(request('per_page', 15)); + ->allowedSorts(['name', 'status', 'id', 'created_at']) + ->defaultSort('-created_at') + ->simplePaginate($request->input('per_page', 15)); return IncidentResource::collection($incidents); } diff --git a/src/Models/Incident.php b/src/Models/Incident.php index b28fc9e3..83840337 100644 --- a/src/Models/Incident.php +++ b/src/Models/Incident.php @@ -171,6 +171,21 @@ public function scopeStickied(Builder $query): void $query->where('stickied', true); } + public function scopeOccursAfter(Builder $query, $date): void + { + $query->where('occurred_at', '>=', $date); + } + + public function scopeOccursBefore(Builder $query, $date): void + { + $query->where('occurred_at', '<=', $date); + } + + public function scopeOccursOn(Builder $query, $date): void + { + $query->whereDate('occurred_at', $date); + } + /** * @return Attribute */ diff --git a/src/Models/MetricPoint.php b/src/Models/MetricPoint.php index fd2e1007..43c2f29c 100644 --- a/src/Models/MetricPoint.php +++ b/src/Models/MetricPoint.php @@ -45,6 +45,7 @@ class MetricPoint extends Model protected $fillable = [ 'value', 'counter', + 'created_at', ]; public function calculatedValue(): Attribute @@ -96,7 +97,7 @@ public function withinThreshold(int $threshold, string|int|DateTime|null $timest $now ??= Carbon::parse($timestamp); - return $this->created_at->startOfMinute()->diffInMinutes($now->startOfMinute()) < $threshold; + return $this->created_at->startOfMinute()->diffInMinutes($now->startOfMinute(), true) < $threshold; } /** diff --git a/tests/Feature/Api/IncidentTest.php b/tests/Feature/Api/IncidentTest.php index 286eac36..411d6389 100644 --- a/tests/Feature/Api/IncidentTest.php +++ b/tests/Feature/Api/IncidentTest.php @@ -147,19 +147,18 @@ it('can filter incidents by occurred at date', function () { Incident::factory(20)->create([ - 'occurred_at' => '2019-01-01', + 'occurred_at' => '2019-01-01 00:00:00', ]); $incident = Incident::factory()->create([ - 'occurred_at' => '2023-01-01', + 'occurred_at' => '2025-01-01 00:00:00', ]); - $query = http_build_query([ + $response = getJson(route('cachet.api.incidents.index', [ 'filter' => [ - 'occurred_at' => '2023-01-01', + 'occurs_after' => '2024-12-31', ], - ]); - - $response = getJson('/status/api/incidents?'.$query); + ])) + ->assertOk(); $response->assertJsonCount(1, 'data'); $response->assertJsonPath('data.0.attributes.id', $incident->id); diff --git a/tests/TestCase.php b/tests/TestCase.php index 1a85fc85..f6835536 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -16,6 +16,7 @@ use Livewire\LivewireServiceProvider; use Orchestra\Testbench\Concerns\WithWorkbench; use Orchestra\Testbench\TestCase as Orchestra; +use Spatie\QueryBuilder\QueryBuilderServiceProvider; abstract class TestCase extends Orchestra { @@ -42,6 +43,7 @@ protected function getPackageProviders($app) BladeHeroiconsServiceProvider::class, WidgetsServiceProvider::class, ScrambleServiceProvider::class, + QueryBuilderServiceProvider::class, ]); // Laravel apps register providers in alphabetical order, so we do the same here for consistency. diff --git a/tests/Unit/Actions/Metric/CreateMetricPointTest.php b/tests/Unit/Actions/Metric/CreateMetricPointTest.php index 2e8f4eae..0e51b753 100644 --- a/tests/Unit/Actions/Metric/CreateMetricPointTest.php +++ b/tests/Unit/Actions/Metric/CreateMetricPointTest.php @@ -106,7 +106,7 @@ expect($point) ->toBeInstanceOf(MetricPoint::class) - ->created_at->isSameAs(Carbon::parse($timestamp)); + ->created_at->toDateTimeString()->toBe(Carbon::parse($timestamp)->toDateTimeString()); })->with([ now()->addWeek()->startOfMinute()->unix(), now()->subHour()->startOfMinute()->toAtomString(),