diff options
author | Daniel Weipert <code@drogueronin.de> | 2023-12-02 14:14:34 +0100 |
---|---|---|
committer | Daniel Weipert <code@drogueronin.de> | 2023-12-02 14:14:34 +0100 |
commit | e5a243a52b910e35b10b26c06aa8978356b86769 (patch) | |
tree | 74ddb82add2f3ea200e9fd11cfedb6c0cace09be | |
parent | fa9096c0ab521aae45cab6c48a54290d14a221b9 (diff) |
login and events
-rw-r--r-- | bin/db.php | 25 | ||||
-rw-r--r-- | src/App.php | 3 | ||||
-rw-r--r-- | src/Controller/Building.php | 4 | ||||
-rw-r--r-- | src/Controller/Event.php | 27 | ||||
-rw-r--r-- | src/Controller/Login.php | 53 | ||||
-rw-r--r-- | src/Controller/Unit.php | 5 | ||||
-rw-r--r-- | src/Controller/Village.php | 20 | ||||
-rw-r--r-- | src/Guard.php | 13 | ||||
-rw-r--r-- | src/Model/Building.php | 23 | ||||
-rw-r--r-- | src/Model/Event/SendUnits.php | 23 | ||||
-rw-r--r-- | src/Model/Event/TrainUnits.php | 4 | ||||
-rw-r--r-- | src/Model/Village.php | 5 | ||||
-rw-r--r-- | src/View.php | 2 | ||||
-rw-r--r-- | views/base.twig | 2 | ||||
-rw-r--r-- | views/error.twig | 8 | ||||
-rw-r--r-- | views/login.twig | 17 | ||||
-rw-r--r-- | views/village.twig | 16 |
17 files changed, 227 insertions, 23 deletions
@@ -115,6 +115,10 @@ DB::query(<<<SQL constraint "relation_event" foreign key ("event_id") references events("id") on delete cascade, + "village_id" bigint not null, + constraint "relation_village" + foreign key ("village_id") references villages("id") on delete cascade, + "type" character varying(255) not null, "created_at" timestamp(0) not null default current_timestamp, @@ -130,6 +134,10 @@ DB::query(<<<SQL constraint "relation_event" foreign key ("event_id") references events("id") on delete cascade, + "village_id" bigint not null, + constraint "relation_village" + foreign key ("village_id") references villages("id") on delete cascade, + "amount" bigint not null, "type" character varying(255) not null, @@ -203,6 +211,23 @@ DB::query(<<<SQL SQL); DB::query(<<<SQL + create table if not exists "user_villages" ( + "id" bigserial primary key, + + "user_id" bigint not null, + constraint "relation_user" + foreign key ("user_id") references users("id") on delete cascade, + + "village_id" bigint not null, + constraint "relation_village" + foreign key ("village_id") references villages("id") on delete cascade, + + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp + ); +SQL); + +DB::query(<<<SQL create table if not exists "system" ( "key" character varying(255) primary key, "value" jsonb diff --git a/src/App.php b/src/App.php index f1fa97e..7524d38 100644 --- a/src/App.php +++ b/src/App.php @@ -11,6 +11,9 @@ class App error_reporting(E_ALL); } + // Session + session_start(); + // DB DB::init(); diff --git a/src/Controller/Building.php b/src/Controller/Building.php index 876f474..e141113 100644 --- a/src/Controller/Building.php +++ b/src/Controller/Building.php @@ -28,7 +28,9 @@ class Building // event $event = new Event(); - $event->time = (new \DateTime())->add(\DateInterval::createFromDateString($building->getBuildTime() . ' seconds')); + $event->time = (new \DateTime())->add(\DateInterval::createFromDateString( + $building->getBuildTimeForLevel($building->getEffectiveLevel() + 1) . ' seconds' + )); $event->villageId = $building->villageId; $upgradeBuildingEvent = new UpgradeBuilding(); $upgradeBuildingEvent->event = $event; diff --git a/src/Controller/Event.php b/src/Controller/Event.php index 78de9d5..1fd304d 100644 --- a/src/Controller/Event.php +++ b/src/Controller/Event.php @@ -31,10 +31,9 @@ class Event $event = DB::fetch(Model::class, 'select * from events where id=:id', ['id' => $request->get('id')])[0] ?? null; $village = Village::get($event->villageId); - if ($event->type === 'SendUnits') { - /**@var SendUnits $sendUnitsEvent*/ - $sendUnitsEvent = DB::fetch(SendUnits::class, 'select * from events_send_units where event_id=:id', ['id' => $event->id]); - + /**@var SendUnits $sendUnitsEvent*/ + $sendUnitsEvent = DB::fetch(SendUnits::class, 'select * from events_send_units where event_id=:id', ['id' => $event->id])[0] ?? null; + if (! empty($sendUnitsEvent)) { if ($sendUnitsEvent->type === 'SendBack') { $cancelTimeDiff = $event->createdAt->diff(new \DateTime()); $cancelTime = (new \DateTime())->add($cancelTimeDiff); @@ -44,7 +43,25 @@ class Event $sendUnitsEvent->residence = $sendUnitsEvent->source; DB::query( - 'update events set time=:time, where id=:id', + 'update events set time=:time where id=:id', + ['time' => $cancelTime->format('c'), 'id' => $request->get('id')] + ); + DB::query( + 'update events_send_units set is_canceled=:is_canceled, home=:home, residence=:residence where id=:id', + ['is_canceled' => $sendUnitsEvent->isCanceled, 'home' => $sendUnitsEvent->home, 'residence' => $sendUnitsEvent->residence, 'id' => $sendUnitsEvent->id] + ); + } + + else if ($sendUnitsEvent->type === 'Recall') { + $cancelTimeDiff = $event->createdAt->diff(new \DateTime()); + $cancelTime = (new \DateTime())->add($cancelTimeDiff); + + $sendUnitsEvent->isCanceled = true; + $sendUnitsEvent->home = $sendUnitsEvent->destination; + $sendUnitsEvent->residence = $sendUnitsEvent->source; + + DB::query( + 'update events set time=:time where id=:id', ['time' => $cancelTime->format('c'), 'id' => $request->get('id')] ); DB::query( diff --git a/src/Controller/Login.php b/src/Controller/Login.php new file mode 100644 index 0000000..0f360ae --- /dev/null +++ b/src/Controller/Login.php @@ -0,0 +1,53 @@ +<?php + +namespace App\Controller; + +use App\DB; +use App\View; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; + +class Login +{ + #[Route(path: '/login', methods: ['GET'])] + public function form(Request $request): Response + { + return new Response(View::render('login.twig')); + } + + #[Route(path: '/login', methods: ['POST'])] + public function login(Request $request): Response + { + $email = $request->get('email'); + $user = DB::query('select id,username,password from users where email=:email', ['email' => $email])->fetch(); + + if (empty($user)) { + $password = password_hash($request->get('password'), PASSWORD_DEFAULT); + DB::query('insert into users (username, password, email) values (:username, :password, :email)', ['username' => $email, 'password' => $password, 'email' => $email]); + } else { + $password = $user['password']; + } + + if (password_verify($request->get('password'), $password)) { + $_SESSION['user'] = [ + 'id' => $user['id'], + 'username' => $user['username'], + ]; + + return new RedirectResponse('/villages'); + } + + return new RedirectResponse('/login'); + } + + #[Route(path: '/logout', methods: ['GET'])] + public function logout(Request $request): Response + { + session_unset(); + session_destroy(); + + return new RedirectResponse('/login'); + } +} diff --git a/src/Controller/Unit.php b/src/Controller/Unit.php index 1774c17..0508249 100644 --- a/src/Controller/Unit.php +++ b/src/Controller/Unit.php @@ -208,6 +208,11 @@ class Unit ); } + DB::query( + 'insert into village_units (amount, type, home_village_id, residence_village_id, is_traveling) values (:amount, :type, :home, :home, true)', + ['amount' => $amount, 'type' => $request->get('unit'), 'home' => $village->id] + ); + // event $event = new Event(); $event->time = (new \DateTime())->add( diff --git a/src/Controller/Village.php b/src/Controller/Village.php index 16a8981..c678779 100644 --- a/src/Controller/Village.php +++ b/src/Controller/Village.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\DB; +use App\Guard; use App\Model\Event\SendUnits; use App\Model\Event\TrainUnits; use App\Model\Event\UpgradeBuilding; @@ -19,7 +20,15 @@ class Village #[Route(path: '/villages', methods: ['GET'])] public function list(): Response { - $villages = DB::fetch(Model::class, "select * from villages"); + $villages = DB::fetch( + Model::class, + <<<SQL + select * from villages + join user_villages on villages.id = user_villages.village_id + where user_villages.user_id=:id + SQL, + ['id' => $_SESSION['user']['id']] + ); return new Response(View::render('villages.twig', [ 'villages' => $villages, @@ -30,6 +39,11 @@ class Village public function show(Request $request): Response { $village = Model::getByCoordinates($request->get('x'), $request->get('y')); + + if (! Guard::ownsVillage($village->id)) { + return new Response(View::render('error.twig', ['message' => 'Insufficient permission']), 403); + } + $events = []; $eventsBuilding = DB::query( @@ -41,7 +55,7 @@ class Village )->fetchAll(); foreach ($eventsBuilding as $row) { - $events['UpgradeBuilding'][] = DB::convertToModel(UpgradeBuilding::class, $row); + $events['UpgradeBuilding'][$row['type']][] = DB::convertToModel(UpgradeBuilding::class, $row); } $eventsUnits = DB::query( @@ -68,7 +82,7 @@ class Village <<<SQL select * from events_send_units as event left join events on event.event_id = events.id - where destination=:id and is_canceled=false + where (destination=:id or source=:id) and village_id!=:id and is_canceled=false SQL, ['id' => $village->id] )->fetchAll(); diff --git a/src/Guard.php b/src/Guard.php new file mode 100644 index 0000000..48f05e1 --- /dev/null +++ b/src/Guard.php @@ -0,0 +1,13 @@ +<?php + +namespace App; + +class Guard +{ + public static function ownsVillage(int $villageId): bool + { + $hasVillage = DB::query('select id from user_villages where user_id=:userId and village_id=:villageId', ['userId' => $_SESSION['user']['id'], 'villageId' => $villageId])->fetchColumn(); + + return ! empty($hasVillage); + } +} diff --git a/src/Model/Building.php b/src/Model/Building.php index 7cae067..eefb4df 100644 --- a/src/Model/Building.php +++ b/src/Model/Building.php @@ -65,13 +65,30 @@ class Building } + public function getEffectiveLevel(): int + { + $upgradeEvents = DB::query( + <<<SQL + select * from events_upgrade_building + inner join events on events.id = events_upgrade_building.event_id + where events.village_id=:villageId and events_upgrade_building.type=:type + SQL, + ['villageId' => $this->villageId, 'type' => $this->type] + )->fetchAll(); + + return $this->level + count($upgradeEvents); + } + public function getBuildTime(): int { - $townHall = Village::getBuilding($this->villageId, 'TownHall'); + return $this->getBuildTimeForLevel($this->level + 1); + } - $nextLevel = $this->level + 1; + public function getBuildTimeForLevel(int $level): int + { + $townHall = Village::getBuilding($this->villageId, 'TownHall'); - return intval($nextLevel * ($nextLevel / $townHall->level) * $_ENV['BASE_BUILDING_BUILD_TIME_FACTOR'] * $this->buildTimeFactor); + return intval($level * ($level / $townHall->level) * $_ENV['BASE_BUILDING_BUILD_TIME_FACTOR'] * $this->buildTimeFactor); } /** diff --git a/src/Model/Event/SendUnits.php b/src/Model/Event/SendUnits.php index ea94442..ed4d5b6 100644 --- a/src/Model/Event/SendUnits.php +++ b/src/Model/Event/SendUnits.php @@ -25,7 +25,7 @@ class SendUnits extends BaseEvent public function __invoke(): void { if ($this->isCanceled) { - if ($this->type === 'SendBack') { + if ($this->type === 'SendBack' || $this->type === 'Recall') { $this->source = $this->home; $this->destination = $this->residence; @@ -54,11 +54,16 @@ class SendUnits extends BaseEvent <<<SQL insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :id, :id) - on conflict (type, home_village_id, residence_village_id) + on conflict (type, home_village_id, residence_village_id, is_traveling) do update set amount = village_units.amount+:amount SQL, ['amount' => $this->amount, 'type' => $this->unit, 'id' => $this->destination] ); + + DB::query( + 'delete from village_units where type=:type and home_village_id=:home and residence_village_id=:residence and is_traveling=true', + ['type' => $this->unit, 'home' => $this->destination, 'residence' => $this->source] + ); } private function borrow(): void @@ -67,11 +72,16 @@ class SendUnits extends BaseEvent <<<SQL insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :home, :residence) - on conflict (type, home_village_id, residence_village_id) + on conflict (type, home_village_id, residence_village_id, is_traveling) do update set amount = village_units.amount+:amount SQL, ['amount' => $this->amount, 'type' => $this->unit, 'home' => $this->source, 'residence' => $this->destination] ); + + DB::query( + 'delete from village_units where type=:type and home_village_id=:home and residence_village_id=:residence and is_traveling=true', + ['type' => $this->unit, 'home' => $this->source, 'residence' => $this->source] + ); } private function gift(): void @@ -80,11 +90,16 @@ class SendUnits extends BaseEvent <<<SQL insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :home, :residence) - on conflict (type, home_village_id, residence_village_id) + on conflict (type, home_village_id, residence_village_id, is_traveling) do update set amount = village_units.amount+:amount SQL, ['amount' => $this->amount, 'type' => $this->unit, 'home' => $this->destination, 'residence' => $this->residence] ); + + DB::query( + 'delete from village_units where type=:type and home_village_id=:home and residence_village_id=:residence and is_traveling=true', + ['type' => $this->unit, 'home' => $this->source, 'residence' => $this->source] + ); } public function dbInsert(): void diff --git a/src/Model/Event/TrainUnits.php b/src/Model/Event/TrainUnits.php index 5b4eef9..5e77198 100644 --- a/src/Model/Event/TrainUnits.php +++ b/src/Model/Event/TrainUnits.php @@ -14,13 +14,13 @@ class TrainUnits extends BaseEvent */ public function __invoke(): void { - $payload = json_decode($this->payload, true); + $this->getEvent(); DB::query( <<<SQL insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) values (:amount, :type, false, :id, :id) - on conflict (type, home_village_id, residence_village_id) + on conflict (type, home_village_id, residence_village_id, is_traveling) do update set amount = village_units.amount+:amount SQL, ['amount' => $this->amount, 'type' => $this->type, 'id' => $this->event->villageId] diff --git a/src/Model/Village.php b/src/Model/Village.php index 6c80ed0..c6709a6 100644 --- a/src/Model/Village.php +++ b/src/Model/Village.php @@ -176,6 +176,11 @@ class Village }); } } + else if ($returnFlag == Village::RETURN_UNIT_EXISTING) { + $units = array_filter($units, function (Unit $unit) { + return ! $unit->isTraveling; + }); + } return array_map(function (Unit $unit) { return $unit->cast(); diff --git a/src/View.php b/src/View.php index 5f9ca34..7862b12 100644 --- a/src/View.php +++ b/src/View.php @@ -24,6 +24,8 @@ class View self::$twig->addFilter(new TwigFilter('buildTime', function ($buildTime) { return @sprintf('%02d:%02d:%02d', $buildTime / 3600, ($buildTime / 60) % 60, $buildTime % 60); })); + + self::$twig->addGlobal('session', $_SESSION); } /** diff --git a/views/base.twig b/views/base.twig index 0063e31..15ddafd 100644 --- a/views/base.twig +++ b/views/base.twig @@ -5,7 +5,9 @@ <header> <nav> <a href="/villages">Overview</a> + <a href="/logout">Logout</a> </nav> + <span>Logged in as {{ session.user.username }}</span> </header> <main> diff --git a/views/error.twig b/views/error.twig new file mode 100644 index 0000000..f9d70cd --- /dev/null +++ b/views/error.twig @@ -0,0 +1,8 @@ +{% extends 'root.twig' %} + +{% block body %} +<div class="wrap"> + {{ message }} + <a href="javascript:history.back()">Back</a> +</div> +{% endblock %} diff --git a/views/login.twig b/views/login.twig new file mode 100644 index 0000000..095f53e --- /dev/null +++ b/views/login.twig @@ -0,0 +1,17 @@ +{% extends 'root.twig' %} + +{% block body %} +<div class="wrap"> + <form action="/login" method="post"> + <label> + E-Mail: + <input type="email" name="email"> + </label> + <label> + Password: + <input type="password" name="password"> + </label> + <button>Login</button> + </form> +</div> +{% endblock %} diff --git a/views/village.twig b/views/village.twig index d2b8a4e..97d65f7 100644 --- a/views/village.twig +++ b/views/village.twig @@ -84,7 +84,8 @@ </tr> </thead> <tbody> - {% for event in events['UpgradeBuilding'] %} + {% for typeEvents in events['UpgradeBuilding'] %} + {% for event in typeEvents %} <tr> <td>{{ event.type }}</td> <td class="timer"> @@ -97,6 +98,7 @@ </td> </tr> {% endfor %} + {% endfor %} </tbody> </table> {% endif %} @@ -190,21 +192,21 @@ <tr class="village__buildings__row"> <td>{{ building.type | default(type) }}</td> <td>{{ building.level | default(0) }}</td> - <td>{{ building.getBuildTime() | buildTime }}</td> + <td>{{ building.getBuildTimeForLevel(building.getEffectiveLevel() + 1) | buildTime }}</td> <td class="resources"> <span> <i class="icon icon-wood"></i> - {{ building.getResourceRequirements()['wood'] }} + {{ building.getResourceRequirementsForLevel(building.getEffectiveLevel() + 1)['wood'] }} </span> <span> <i class="icon icon-clay"></i> - {{ building.getResourceRequirements()['clay'] }} + {{ building.getResourceRequirementsForLevel(building.getEffectiveLevel() + 1)['clay'] }} </span> <span> <i class="icon icon-iron"></i> - {{ building.getResourceRequirements()['iron'] }} + {{ building.getResourceRequirementsForLevel(building.getEffectiveLevel() + 1)['iron'] }} </span> </td> <td> @@ -235,6 +237,7 @@ <tr> <td>{{ unit.type }}</td> <td>{{ unit.amount }}</td> + {% if not unit.isTraveling %} <td> {{ unit.getBuildTime(1) | buildTime }} </td> @@ -265,6 +268,9 @@ <input type="submit" value="Train" {{ village.canTrain(village, unit, 1) ? '' : 'disabled' }}> </form> </td> + {% else %} + <td>~traveling~</td> + {% endif %} </tr> {% endfor %} </tbody> |