summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <code@drogueronin.de>2023-12-02 14:14:34 +0100
committerDaniel Weipert <code@drogueronin.de>2023-12-02 14:14:34 +0100
commite5a243a52b910e35b10b26c06aa8978356b86769 (patch)
tree74ddb82add2f3ea200e9fd11cfedb6c0cace09be
parentfa9096c0ab521aae45cab6c48a54290d14a221b9 (diff)
login and events
-rw-r--r--bin/db.php25
-rw-r--r--src/App.php3
-rw-r--r--src/Controller/Building.php4
-rw-r--r--src/Controller/Event.php27
-rw-r--r--src/Controller/Login.php53
-rw-r--r--src/Controller/Unit.php5
-rw-r--r--src/Controller/Village.php20
-rw-r--r--src/Guard.php13
-rw-r--r--src/Model/Building.php23
-rw-r--r--src/Model/Event/SendUnits.php23
-rw-r--r--src/Model/Event/TrainUnits.php4
-rw-r--r--src/Model/Village.php5
-rw-r--r--src/View.php2
-rw-r--r--views/base.twig2
-rw-r--r--views/error.twig8
-rw-r--r--views/login.twig17
-rw-r--r--views/village.twig16
17 files changed, 227 insertions, 23 deletions
diff --git a/bin/db.php b/bin/db.php
index 7f3f344..84cb85c 100644
--- a/bin/db.php
+++ b/bin/db.php
@@ -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>
&nbsp;
<span>
<i class="icon icon-clay"></i>
- {{ building.getResourceRequirements()['clay'] }}
+ {{ building.getResourceRequirementsForLevel(building.getEffectiveLevel() + 1)['clay'] }}
</span>
&nbsp;
<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>