This repository has been archived by the owner on May 20, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1857fbb
commit 9bb74bb
Showing
5 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
app/Modules/User/Interfaces/Console/Commands/CreateUser.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Modules\User\Interfaces\Console\Commands; | ||
|
||
use Cycle\ORM\ORMInterface; | ||
use Cycle\ORM\TransactionInterface; | ||
use Illuminate\Console\Command; | ||
use Illuminate\Support\Facades\Hash; | ||
use Illuminate\Support\Str; | ||
use Modules\User\Domain\User; | ||
|
||
class CreateUser extends Command | ||
{ | ||
protected $signature = 'user:create {username?} {password?}'; | ||
|
||
public function handle(TransactionInterface $transaction, ORMInterface $orm) | ||
{ | ||
if (! config('auth.enabled')) { | ||
$this->error('Authentication is disabled.'); | ||
|
||
return; | ||
} | ||
|
||
$username = $this->argument('username') ?? env('AUTH_USERNAME', 'admin'); | ||
$password = $this->argument('password') ?? env('AUTH_PASSWORD', Str::random(8)); | ||
|
||
|
||
$user = $orm->getRepository(User::class)->findOne(['name' => $username]); | ||
if ($user) { | ||
$this->error(sprintf('User with given username [%s] exists. Try another name.', $username)); | ||
|
||
return; | ||
} | ||
|
||
$transaction->persist(new User($username, Hash::make($password))); | ||
$transaction->run(); | ||
|
||
$this->info('User created.'); | ||
$this->table([], [ | ||
['Username', $username], | ||
['Password', $password], | ||
]); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
database/cycle/migrations/20211125.185332_0_0_default_create_users.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
namespace Migration; | ||
|
||
use Cycle\Migrations\Migration; | ||
|
||
class OrmDefault1e5a31b92337b8a5a635afa30098a402 extends Migration | ||
{ | ||
protected const DATABASE = 'default'; | ||
|
||
public function up(): void | ||
{ | ||
$this->table('users') | ||
->addColumn('remember_token', 'string', [ | ||
'nullable' => false, | ||
'default' => null, | ||
]) | ||
->addColumn('uuid', 'string', [ | ||
'nullable' => false, | ||
'default' => null, | ||
]) | ||
->addColumn('name', 'string', [ | ||
'nullable' => false, | ||
'default' => null, | ||
]) | ||
->addColumn('password', 'string', [ | ||
'nullable' => false, | ||
'default' => null, | ||
]) | ||
->addIndex(["name"], [ | ||
'name' => 'users_index_name_619fdbaa03862', | ||
'unique' => true, | ||
]) | ||
->setPrimaryKeys(["uuid"]) | ||
->create(); | ||
} | ||
|
||
public function down(): void | ||
{ | ||
$this->table('users')->drop(); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
database/cycle/migrations/20211125.185333_0_0_default_create_stored_events.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
namespace Migration; | ||
|
||
use Cycle\Migrations\Migration; | ||
|
||
class OrmDefault1e5a31b92337b8a5a635afa30098a403 extends Migration | ||
{ | ||
protected const DATABASE = 'default'; | ||
|
||
public function up(): void | ||
{ | ||
$this->table('stored_events') | ||
->addColumn('event_id', 'string', [ | ||
'nullable' => false, | ||
'default' => null | ||
]) | ||
->addColumn('event_type', 'string', [ | ||
'nullable' => false, | ||
'default' => null | ||
]) | ||
->addColumn('aggregate_root_id', 'string', [ | ||
'nullable' => false, | ||
'default' => null | ||
]) | ||
->addColumn('version', 'integer', [ | ||
'nullable' => false, | ||
'default' => null | ||
]) | ||
->addColumn('payload', 'json', [ | ||
'nullable' => false, | ||
'default' => null | ||
]) | ||
->setPrimaryKeys(["event_id"]) | ||
->create(); | ||
} | ||
|
||
public function down(): void | ||
{ | ||
$this->table('stored_events')->drop(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<template> | ||
<div class="h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> | ||
<div class="max-w-sm w-full space-y-8"> | ||
<div class="flex flex-col items-center"> | ||
<svg class="text-blue-600 fill-current w-2/3" xmlns="http:https://www.w3.org/2000/svg" viewBox="0 0 117 24"> | ||
<path | ||
d="M46.3 12.6c0 1.5-.2 2.7-.7 3.4-.5.8-1.3 1.2-2.3 1.2-.9 0-1.5-.4-2-1.1l-.1.9h-2.3V3.5h2.5v4.8c.5-.7 1-1 1.8-1 1.1 0 1.9.4 2.4 1.2.5.7.7 1.8.7 3.3v.8Zm-2.5-.7c0-1 0-1.6-.3-2-.1-.3-.5-.5-1-.5s-.9.2-1.1.7v4.3c.2.5.6.7 1.2.7.4 0 .8-.1 1-.5l.2-1.8V12ZM51.6 16.1c-.5.7-1.2 1-2 1-1 0-1.6-.2-2-.8-.5-.6-.7-1.5-.7-2.6V7.5h2.4v6.2c0 1 .4 1.4 1 1.4.5 0 1-.2 1.2-.7v-7H54V17h-2.3l-.1-.9ZM54.6 12c0-1.6.3-2.8.8-3.5.6-.8 1.4-1.2 2.4-1.2.8 0 1.5.4 2 1v-.8h2.3V17c0 1.2-.3 2.1-1 2.8-.7.6-1.7 1-3 1l-1.6-.4a3 3 0 0 1-1.3-.8l.9-1.7c.2.3.5.5.9.6.4.2.7.2 1 .2.6 0 1 0 1.3-.4.2-.2.3-.6.3-1.2v-.9c-.4.7-1 1-1.8 1-1 0-1.8-.4-2.4-1.2-.5-.8-.8-2-.8-3.3V12Zm2.5.6c0 .9 0 1.5.3 1.9.2.4.6.6 1.1.6.5 0 .9-.2 1.1-.6V10c-.2-.4-.6-.6-1-.6-.6 0-1 .2-1.2.6a4 4 0 0 0-.3 2v.6ZM62.7 12c0-1.6.3-2.8.9-3.5.5-.8 1.3-1.2 2.3-1.2.9 0 1.6.4 2 1l.1-.8h2.3V17c0 1.2-.4 2.1-1 2.8-.7.6-1.7 1-3 1-.5 0-1-.2-1.6-.4a3 3 0 0 1-1.3-.8l.8-1.7c.3.3.6.5 1 .6.3.2.7.2 1 .2.6 0 1 0 1.2-.4.3-.2.4-.6.4-1.2v-.9c-.5.7-1.1 1-1.9 1-1 0-1.8-.4-2.3-1.2-.6-.8-.9-2-.9-3.3V12Zm2.5.6c0 .9.1 1.5.4 1.9.2.4.6.6 1 .6.6 0 1-.2 1.2-.6V10c-.3-.4-.6-.6-1.1-.6-.5 0-.9.2-1.1.6a4 4 0 0 0-.4 2v.6ZM75.9 9.9H75c-.6 0-1 .2-1.3.8V17h-2.5V7.5h2.3v1c.5-.8 1-1.2 1.7-1.2l.7.1V10ZM80 17.2c-1.4 0-2.3-.4-3-1.2-.8-.7-1.1-1.8-1.1-3.2V12c0-1.5.3-2.6 1-3.5.6-.8 1.5-1.2 2.8-1.2 1.2 0 2 .4 2.7 1.2.6.7.9 1.9.9 3.4V13h-5c0 .7.2 1.2.5 1.5.3.3.7.5 1.3.5.8 0 1.5-.3 2-.8l1 1.5c-.3.4-.7.7-1.3 1-.6.2-1.2.4-1.9.4Zm-1.6-5.9h2.4v-.2c0-.6 0-1-.2-1.3-.2-.3-.5-.4-1-.4-.4 0-.7.1-.9.4-.2.4-.3.9-.3 1.5ZM83.5 12c0-1.6.3-2.8.8-3.5.6-.8 1.4-1.2 2.4-1.2.9 0 1.5.4 2 1l.1-.8H91V17c0 1.2-.3 2.1-1 2.8-.7.6-1.6 1-3 1l-1.6-.4a3 3 0 0 1-1.2-.8L85 18c.2.3.5.5 1 .6.3.2.6.2 1 .2.5 0 1 0 1.2-.4.2-.2.3-.6.4-1.2v-.9c-.5.7-1.1 1-1.9 1-1 0-1.8-.4-2.4-1.2-.5-.8-.8-2-.8-3.3V12Zm2.5.6c0 .9.1 1.5.3 1.9.3.4.6.6 1.1.6.5 0 1-.2 1.2-.6V10c-.3-.4-.7-.6-1.2-.6s-.8.2-1 .6a4 4 0 0 0-.4 2v.6ZM96.5 17l-.2-.7c-.5.6-1 .9-1.9.9-.8 0-1.4-.3-2-.8-.5-.5-.7-1.2-.7-2 0-1 .3-1.8 1-2.4.6-.5 1.5-.8 2.7-.8h.7v-.8c0-.4 0-.7-.2-.9-.1-.2-.3-.2-.6-.2-.6 0-1 .3-1 1H92c0-.8.3-1.6 1-2.1.6-.6 1.4-.9 2.4-.9s1.9.3 2.5.8c.5.6.8 1.3.8 2.4v4.4c0 .8.1 1.5.4 2v.1h-2.5ZM95 15.2l.7-.1.4-.4v-2h-.6c-.4 0-.7.1-1 .4-.2.3-.3.6-.3 1 0 .8.2 1.1.8 1.1ZM102.4 5.2v2.3h1.3v1.9h-1.3V14c0 .4 0 .6.2.8l.6.2.5-.1v2l-1.3.2c-1.6 0-2.5-1-2.5-2.8v-5h-1v-2h1V5.3h2.5Z"/> | ||
<path | ||
d="M103.6 12c0-1.5.3-2.6 1-3.5.7-.8 1.6-1.2 2.8-1.2 1.3 0 2.2.4 2.9 1.2.7.9 1 2 1 3.5v.6c0 1.4-.3 2.5-1 3.4-.7.8-1.6 1.2-2.8 1.2-1.3 0-2.2-.4-2.9-1.2-.7-.9-1-2-1-3.5V12Zm2.5.6c0 1.7.5 2.5 1.4 2.5.8 0 1.3-.7 1.3-2.1v-1a4 4 0 0 0-.3-2c-.3-.4-.6-.6-1-.6-.5 0-.8.2-1 .6a4 4 0 0 0-.4 2v.6ZM116.7 9.9h-.9c-.7 0-1.1.2-1.4.8V17H112V7.5h2.3v1c.5-.8 1-1.2 1.7-1.2l.7.1V10ZM7.1 23.1c-1.3-.3-2.3-1-3-1.8-.6-.9-1-2-1-3.4v-2.3c0-1.8-.8-2.7-2.4-2.7v-1.7c1.6 0 2.4-.9 2.4-2.7V6c0-1.3.4-2.4 1-3.3.7-.8 1.7-1.5 3-1.8l.5 1.3C6 2.8 5.2 4 5.2 6.2v2.3c0 1.7-.6 2.9-1.9 3.6 1.3.6 2 1.8 2 3.6V18c0 2 .7 3.3 2.3 3.8L7 23.1ZM25.3 21.8c1.5-.5 2.3-1.7 2.4-3.7v-2.5c0-1.7.6-3 2-3.5-1.4-.7-2-1.9-2-3.6V6.2c0-2.1-.8-3.4-2.4-4l.4-1.2c1.4.3 2.4 1 3 1.8.7.8 1 2 1 3.4v2.3c0 1.8.8 2.7 2.4 2.7V13c-1.6 0-2.4.9-2.4 2.7V18c0 1.4-.3 2.5-1 3.4-.7.8-1.7 1.5-3 1.8l-.4-1.3Z"/> | ||
<path fill-rule="evenodd" clip-rule="evenodd" | ||
d="M11.4 7.6a4.7 4.7 0 0 1 9.4 0V8l1.6-1.7a.6.6 0 1 1 .8.7l-1.5 1.7c.5.5.7 1.1.7 1.8v1.4l-.1.8h2a.6.6 0 0 1 0 1.2h-2.2c-.2 1-.5 2-1 2.8l-.4 1-.1.1 2 2.1a.6.6 0 0 1-.8.8l-1.9-2a5.3 5.3 0 0 1-8-.2l-2.1 2a.6.6 0 1 1-.8-.8l2.2-2.2-.6-1.4c-.3-.7-.6-1.5-.7-2.2H7.6a.6.6 0 1 1 0-1.2h2v-2.1c-.1-.7.1-1.3.5-1.8L8.5 7a.6.6 0 0 1 .9-.8L11 8l.4-.2v-.2Zm7.7 0v.1h-6a3 3 0 0 1 6 0Zm.6 1.8h-7.5a1 1 0 0 0-1 1l.1 1.5c0 1.2.4 2.3.8 3.4l.6 1.3a3.6 3.6 0 0 0 6.5.2l.4-1c.7-1.2 1-2.6 1-4v-1.4c.1-.6-.3-1-.9-1Z"/> | ||
<path fill-rule="evenodd" clip-rule="evenodd" | ||
d="M17.8 10.5a.6.6 0 0 1 .8.8L16.8 13l2 2a.6.6 0 1 1-.9.7l-1.9-2-2 2a.6.6 0 1 1-.7-.8l1.9-2-1.8-1.7a.6.6 0 0 1 .8-.8l1.8 1.8 1.8-1.8Z"/> | ||
</svg> | ||
<h2 class="mt-6 text-2xl text-gray-600 font-bold">Sign-in</h2> | ||
</div> | ||
<form @submit.prevent="submit" class="mt-8 space-y-6"> | ||
<div v-if="hasErrors" class="bg-gray-50 border p-5"> | ||
<div class="font-bold text-red-600">Whoops! Something went wrong.</div> | ||
|
||
<ul class="mt-3 list-disc list-inside text-sm text-red-600"> | ||
<li v-for="(error, key) in errors" :key="key">{{ error }}</li> | ||
</ul> | ||
</div> | ||
|
||
<div> | ||
<label for="username" class="sr-only">Username</label> | ||
<input id="username" | ||
v-model="form.name" | ||
type="text" | ||
required | ||
class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 font-bold focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm" | ||
placeholder="Username"> | ||
</div> | ||
<div> | ||
<label for="password" class="sr-only">Password</label> | ||
<input id="password" | ||
v-model="form.password" | ||
type="password" | ||
autocomplete="current-password" | ||
required | ||
class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 font-bold focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm" | ||
placeholder="Password"> | ||
</div> | ||
|
||
<div class="flex items-center"> | ||
<button type="submit" | ||
class="group relative flex justify-center py-2 px-4 border border-transparent text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | ||
Sign in | ||
</button> | ||
|
||
<div class="flex items-center ml-5"> | ||
<input id="remember-me" name="remember-me" v-model="form.remember" type="checkbox" | ||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"> | ||
<label for="remember-me" class="ml-2 block text-sm text-gray-600">Remember me</label> | ||
</div> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import {computed, defineComponent} from 'vue' | ||
import {usePage} from "@inertiajs/inertia-vue3"; | ||
export default defineComponent({ | ||
setup() { | ||
const version = computed(() => usePage().props.value.version) | ||
const name = computed(() => usePage().props.value.name) | ||
return {version, name} | ||
}, | ||
data() { | ||
return { | ||
form: this.$inertia.form({ | ||
name: '', | ||
password: '', | ||
remember: false | ||
}) | ||
} | ||
}, | ||
methods: { | ||
submit() { | ||
this.form | ||
.transform(data => ({ | ||
...data, | ||
remember: this.form.remember ? 'on' : '' | ||
})) | ||
.post(this.route('login'), { | ||
onFinish: () => this.form.reset('password'), | ||
}) | ||
} | ||
}, | ||
computed: { | ||
errors() { | ||
return this.$page.props.errors | ||
}, | ||
hasErrors() { | ||
return Object.keys(this.errors).length > 0; | ||
}, | ||
} | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Tests\Feature\Http; | ||
|
||
use App\Domain\ValueObjects\Uuid; | ||
use Tests\DatabaseTestCase; | ||
|
||
class EventsWithAuthControllerTest extends DatabaseTestCase | ||
{ | ||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
config()->set('auth.enabled', true); | ||
} | ||
|
||
public function testGetListOfEvents() | ||
{ | ||
$this->getJson(route('events'), ['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()]) | ||
->assertUnauthorized(); | ||
} | ||
|
||
public function testGetSpecificTypeListOfEventsForUnknownTypeEventShouldReturnNotFound() | ||
{ | ||
$this->getJson(route('events.type', 'foo'), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertForbidden(); | ||
} | ||
|
||
public function testGetSpecificTypeListOfEvents() | ||
{ | ||
$event = $this->createEvent('test', []); | ||
$this->getJson( | ||
route('events.type', $event->getType()), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertForbidden(); | ||
} | ||
|
||
public function testDeleteAllEvents() | ||
{ | ||
$this->getJson( | ||
route('events'), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertUnauthorized(); | ||
} | ||
|
||
public function testDeleteSpecificTypeEvents() | ||
{ | ||
$this->getJson( | ||
route('events'), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertUnauthorized(); | ||
} | ||
|
||
public function testDeleteEventByUuid() | ||
{ | ||
$event = $this->createEvent('bar', ['foo1' => 'bar1']); | ||
$this->deleteJson(route('event.delete', $event->getUuid()->toString())) | ||
->assertUnauthorized(); | ||
} | ||
|
||
public function testGetEventJsonByUuid() | ||
{ | ||
$event = $this->createEvent('bar', ['foo1' => 'bar1']); | ||
$this->getJson(route('event.show.json', $event->getUuid()->toString())) | ||
->assertUnauthorized(); | ||
} | ||
|
||
public function testGetEventJsonShouldReturn404IfNotFound() | ||
{ | ||
$this->getJson(route('event.show.json', Uuid::generate()->toString())) | ||
->assertUnauthorized(); | ||
} | ||
|
||
public function testGetEventByUuid() | ||
{ | ||
config()->set('server.foo.http.show', 'Foo/Show'); | ||
$event = $this->createEvent('foo', ['foo1' => 'bar1']); | ||
$this->getJson( | ||
route('event.show', [$event->getType(), $event->getUuid()->toString()]), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertUnauthorized(); | ||
} | ||
|
||
public function testGetEventShouldReturn404IfNotFound() | ||
{ | ||
config()->set('server.foo.http.show', 'Foo/Show'); | ||
$this->getJson( | ||
route('event.show', ['foo', Uuid::generate()->toString()]), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertUnauthorized(); | ||
} | ||
|
||
public function testGetEventShouldReturn404IfWrongType() | ||
{ | ||
$this->getJson( | ||
route('event.show', ['foo', Uuid::generate()->toString()]), | ||
['X-Inertia' => true, 'X-Inertia-Version' => $this->inertiaVersion()] | ||
)->assertUnauthorized(); | ||
} | ||
} |