diff --git a/README.md b/README.md index 9364fe9..b8459e8 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,20 @@ # AIssue for Laravel +Basic and Lean Issue Management Package for Laravel + [![Latest Version on Packagist](https://img.shields.io/packagist/v/aurorawebsoftware/aissue.svg?style=flat-square)](https://packagist.org/packages/aurorawebsoftware/aissue) [![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/aurorawebsoftware/aissue/run-tests?label=tests)](https://github.com/aurorawebsoftware/aissue/actions?query=workflow%3Arun-tests+branch%3Amain) [![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/aurorawebsoftware/aissue/Check%20&%20fix%20styling?label=code%20style)](https://github.com/aurorawebsoftware/aissue/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) [![Total Downloads](https://img.shields.io/packagist/dt/aurorawebsoftware/aissue.svg?style=flat-square)](https://packagist.org/packages/aurora/aissue) -Todo .... # Features -- Todo ... - +- Basic Workflow and Issue Management +- Limitless Issue Types +- Limitless Statuses for Issue Types +- Authenticatable Issue Status Transitions +- Easy to Use and Lean --- @@ -24,15 +28,15 @@ You can install the package via composer: composer require aurorawebsoftware/aissue ``` -Todo +You must add AIssueModelTrait Trait to the **Issueable** Model and The model must implement **AIssueModelContract** ```php -use Illuminate\Foundation\Auth\User as Authenticatable; -use AuroraWebSoftware\aissue\Traits\aissueUser; +use AuroraWebSoftware\AIssue\Contracts\AIssueModelContract; +use AuroraWebSoftware\AIssue\Traits\AIssueModelTrait; -class User extends Authenticatable +class Issueable extends Model implements AIssueModelContract { - use ; + use AIssueModelTrait;; // ... } @@ -44,19 +48,6 @@ You can publish and run the migrations with: php artisan migrate ``` -You can publish the sample data seeder with: - -```bash -php artisan vendor:publish --tag="aissue-seeders" -php artisan db:seed --class=SampleDataSeeder -``` - -Optionally, You can seed the sample data with: - -```bash -php artisan db:seed --class=SampleDataSeeder -``` - You can publish the config file with: ```bash @@ -64,23 +55,29 @@ php artisan vendor:publish --tag="aissue-config" ``` This is the example contents of the published config file: +```bash -```php -return [ -]; + return [ + 'policyMethod' => fn ($permission): bool => true, + 'issueTypes' => [ + 'task' => [ + 'todo' => ['sort' => 1, 'permission' => 'todo_perm'], + 'in_progress' => ['sort' => 2, 'permission' => 'in_progress_perm'], + 'done' => ['sort' => 3, 'permission' => 'done_perm'], + ], + ], + ]; ``` -# Main Philosophy -Todo +**Permission Config File** + +Permissions are stored `config/aissue.php` is published after installing ---- -> If you don't need organizational roles, **aissue** may not be suitable for your work. ---- # Aissue Terminology -Before using aissue its worth to understand the main terminology of aissue. -aissue differs from other Auth Packages due to its organizational structure. +Before using AIssue its worth to understand the main terminology of AIssue. +The difference of Issue from other packages is that it perform simple-level workflows with its simplified structure. # Usage @@ -88,12 +85,66 @@ aissue differs from other Auth Packages due to its organizational structure. Before using this, please make sure that you published the config files. -## aissue Service and Facade Methods +## AIssue Services, Service Provider and Facade -### todo +// todo +### Creating an Issuable ```php +$createdModel = Issueable::create( + ['name' => 'example isuable model'] + ); +``` + +### Making a transition for todo, in_progres and done +```php + + $createdModel = Issueable::create( + ['name' => 'example isuable model'] + ); + + /** @var AIssue $createdIssueModel */ + $createdIssueModel = $createdModel->createIssue(1, 1, 'example', 'example isssue', 'example', 1, \Illuminate\Support\Carbon::now()); + //todo,in_progress,done + $createdIssueModel->canMakeTransition('todo') + +``` + +### Getting transitionable statuses +```php + + $createdModel = Issueable::create( + ['name' => 'example isuable model 4'] + ); + + /** @var AIssue $createdIssueModel */ + $createdIssueModel = $createdModel->createIssue(1, 1, 'example', 'example isssue', 'example', 1, \Illuminate\Support\Carbon::now()); + $transitionable = $createdIssueModel->getTransitionableStatuses($createdIssueModel); + + $this->assertTrue($transitionable == ["todo","in_progress"]); + +``` + +### Using AIssue Interface and Trait with Eloquent Models +To turn an Eloquent Model into an AIssue ; +Model must implement AIssueModelContract and use AIssueModelTrait Trait. +After adding AIssueModelContract trait, you will be able to use AIssue methods within the model +```php + + namespace App\Models\ExampleModel; + + use AuroraWebSoftware\AIssue\Contracts\AIssueModelContract; + use AuroraWebSoftware\AIssue\Traits\AIssueModelTrait; + use Illuminate\Database\Eloquent\Model; + + class ExampleModel extends Model implements AIssueModelContract + { + use AIssueModelTrait; + + // implementation +} + ``` @@ -107,7 +158,6 @@ Please see [CONTRIBUTING](README-contr.md) for details. ## Security Vulnerabilities -// todo ? Please review [our security policy](../../security/policy) on how to report security vulnerabilities. diff --git a/src/AIssue.php b/src/AIssue.php index 4abcd38..c21c032 100755 --- a/src/AIssue.php +++ b/src/AIssue.php @@ -42,8 +42,9 @@ public function makeTransition(Models\AIssue $issue, string $status): Models\AIs if ($this->canMakeTransition($issue, $status)) { $issue->status = $status; $issue->save(); - } + return $issue; + } throw new TransitionPermissionException(); } diff --git a/src/AIssueServiceProvider.php b/src/AIssueServiceProvider.php index 7694069..62c6ff6 100644 --- a/src/AIssueServiceProvider.php +++ b/src/AIssueServiceProvider.php @@ -28,7 +28,6 @@ public function boot(): void parent::boot(); // load packages migrations $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); - $this->publishes([ __DIR__.'/../config' => config_path(), ], 'aissue-config'); diff --git a/src/Exceptions/IssueTypeNotFoundException.php b/src/Exceptions/IssueTypeNotFoundException.php new file mode 100644 index 0000000..6391bbb --- /dev/null +++ b/src/Exceptions/IssueTypeNotFoundException.php @@ -0,0 +1,9 @@ +set('database.default', 'testing'); - config()->set('database.default', 'mysql'); + config()->set('database.default', 'testing'); + // config()->set('database.default', 'mysql'); /* $migration = include __DIR__.'/../database/migrations/create_aissue_table.php.stub'; diff --git a/tests/Unit/AIssueTest.php b/tests/Unit/AIssueTest.php index e28469e..c1714ca 100644 --- a/tests/Unit/AIssueTest.php +++ b/tests/Unit/AIssueTest.php @@ -1,8 +1,10 @@ assertTrue(config('aissue')['policyMethod']('todo_perm')); }); -test('can get one specified issue', function () { - //AAuth::organizationNodes(); - // todo - expect(1)->toBeTruthy(); +test('can access policy method works for done', function () { + $this->assertFalse(config('aissue')['policyMethod']('done_perm')); }); -test('can create aissue for a model', function () { +test('can create aissue for a model using trait', function () { $createdModel = Issueable::create( ['name' => 'test isuable model 1'] ); - $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 1.1', 'asdasd', 1, \Illuminate\Support\Carbon::now()); + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 1.1', 'asdasd', 1, Carbon::now()); $this->assertEquals( AIssue::where('id', '=', $createdIssueModel->id)->first()->summary, @@ -58,24 +58,24 @@ ); }); -test('can check make transition for todo', function () { +test('can check make transition for todo using trait', function () { $createdModel = Issueable::create( ['name' => 'test isuable model 2'] ); /** @var AIssue $createdIssueModel */ - $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, \Illuminate\Support\Carbon::now()); + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, Carbon::now()); $this->assertTrue($createdIssueModel->canMakeTransition('todo')); }); -test('can check make transition for in_progress', function () { +test('can check make transition for in_progress using trait', function () { $createdModel = Issueable::create( ['name' => 'test isuable model 3'] ); /** @var AIssue $createdIssueModel */ - $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, \Illuminate\Support\Carbon::now()); + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, Carbon::now()); $this->assertTrue($createdIssueModel->canMakeTransition('in_progress')); }); @@ -86,7 +86,197 @@ ); /** @var AIssue $createdIssueModel */ - $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, \Illuminate\Support\Carbon::now()); + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, Carbon::now()); $this->assertFalse($createdIssueModel->canMakeTransition('done')); }); + +test('can make transition using Issue Model', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 5'] + ); + + /** @var AIssue $createdIssueModel */ + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, Carbon::now()); + + $transition = $createdIssueModel->makeTransition('in_progress'); + + $this->assertTrue($transition->status == 'in_progress'); +}); + +test('cannot make transition using Issue Model without permission', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 5'] + ); + + /** @var AIssue $createdIssueModel */ + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, Carbon::now()); + + $transition = $createdIssueModel->makeTransition('done'); +})->throws(TransitionPermissionException::class); + +test('can check get transitionable statuses ', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 4'] + ); + + /** @var AIssue $createdIssueModel */ + $createdIssueModel = $createdModel->createIssue(1, 1, 'task', 'test isssue 2.1', 'asdasd', 1, Carbon::now()); + $transitionable = $createdIssueModel->getTransitionableStatuses($createdIssueModel); + $this->assertTrue($transitionable == ['todo', 'in_progress']); +}); + +test('can create aissue using service class', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 1 service class'] + ); + + $aissueService = new AuroraWebSoftware\AIssue\AIssue; + + $data = [ + 'model_type' => $createdModel->getAIssueModelType(), + 'model_id' => $createdModel->getAIssueModelId(), + 'assignee_id' => 1, + 'creater_id' => 1, + 'issue_type' => 'task', + 'summary' => 'test isssue service class', + 'description' => 'asdasd', + 'priority' => 1, + 'status' => $createdModel->getAIssueDefaultStatus('task'), + 'duedate' => Carbon::now(), + ]; + + $createdIssueModel = $aissueService->createIssue($data); + $this->assertEquals( + AIssue::where('id', '=', $createdIssueModel->id)->first()->summary, + $createdIssueModel->summary + ); +}); + +test('can check make transition for todo using service class', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 2 service class'] + ); + + $aissueService = new AuroraWebSoftware\AIssue\AIssue; + + $data = [ + 'model_type' => $createdModel->getAIssueModelType(), + 'model_id' => $createdModel->getAIssueModelId(), + 'assignee_id' => 1, + 'creater_id' => 1, + 'issue_type' => 'task', + 'summary' => 'test isssue service class', + 'description' => 'asdasd', + 'priority' => 1, + 'status' => $createdModel->getAIssueDefaultStatus('task'), + 'duedate' => Carbon::now(), + ]; + + $createdIssueModel = $aissueService->createIssue($data); + + $this->assertTrue($createdIssueModel->canMakeTransition('todo')); +}); + +test('can check make transition for in_progress using service class', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 3 service class'] + ); + + $aissueService = new AuroraWebSoftware\AIssue\AIssue; + + $data = [ + 'model_type' => $createdModel->getAIssueModelType(), + 'model_id' => $createdModel->getAIssueModelId(), + 'assignee_id' => 1, + 'creater_id' => 1, + 'issue_type' => 'task', + 'summary' => 'test isssue service class', + 'description' => 'asdasd', + 'priority' => 1, + 'status' => $createdModel->getAIssueDefaultStatus('task'), + 'duedate' => Carbon::now(), + ]; + + $createdIssueModel = $aissueService->createIssue($data); + $this->assertTrue($createdIssueModel->canMakeTransition('in_progress')); +}); + +test('can check make transition for done from service class', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 4 service class'] + ); + + $aissueService = new AuroraWebSoftware\AIssue\AIssue; + + $data = [ + 'model_type' => $createdModel->getAIssueModelType(), + 'model_id' => $createdModel->getAIssueModelId(), + 'assignee_id' => 1, + 'creater_id' => 1, + 'issue_type' => 'task', + 'summary' => 'test isssue service class', + 'description' => 'asdasd', + 'priority' => 1, + 'status' => $createdModel->getAIssueDefaultStatus('task'), + 'duedate' => Carbon::now(), + ]; + + $createdIssueModel = $aissueService->createIssue($data); + $this->assertFalse($createdIssueModel->canMakeTransition('done')); +}); + +test('can make transition using service class', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 5 service class'] + ); + + $aissueService = new AuroraWebSoftware\AIssue\AIssue; + + $data = [ + 'model_type' => $createdModel->getAIssueModelType(), + 'model_id' => $createdModel->getAIssueModelId(), + 'assignee_id' => 1, + 'creater_id' => 1, + 'issue_type' => 'task', + 'summary' => 'test isssue service class', + 'description' => 'asdasd', + 'priority' => 1, + 'status' => $createdModel->getAIssueDefaultStatus('task'), + 'duedate' => Carbon::now(), + ]; + + $createdIssueModel = $aissueService->createIssue($data); + + $transition = $createdIssueModel->makeTransition('in_progress'); + + $this->assertTrue($transition->status == 'in_progress'); +}); + +test('can check get transitionable statuses from service class', function () { + $createdModel = Issueable::create( + ['name' => 'test isuable model 4 service class'] + ); + + $aissueService = new AuroraWebSoftware\AIssue\AIssue; + + $data = [ + 'model_type' => $createdModel->getAIssueModelType(), + 'model_id' => $createdModel->getAIssueModelId(), + 'assignee_id' => 1, + 'creater_id' => 1, + 'issue_type' => 'task', + 'summary' => 'test isssue service class', + 'description' => 'asdasd', + 'priority' => 1, + 'status' => $createdModel->getAIssueDefaultStatus('task'), + 'duedate' => Carbon::now(), + ]; + + $createdIssueModel = $aissueService->createIssue($data); + + $transitionable = $createdIssueModel->getTransitionableStatuses($createdIssueModel); + $this->assertTrue($transitionable == ['todo', 'in_progress']); +}); + +// todo all Facade Class tests must be written.