mirror of https://github.com/kevachat/webapp.git
![localhost](/assets/img/avatar_default.png)
25 changed files with 895 additions and 36 deletions
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
version: '3' |
||||
|
||||
services: |
||||
###> doctrine/doctrine-bundle ### |
||||
database: |
||||
ports: |
||||
- "5432" |
||||
###< doctrine/doctrine-bundle ### |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
version: '3' |
||||
|
||||
services: |
||||
###> doctrine/doctrine-bundle ### |
||||
database: |
||||
image: postgres:${POSTGRES_VERSION:-16}-alpine |
||||
environment: |
||||
POSTGRES_DB: ${POSTGRES_DB:-app} |
||||
# You should definitely change the password in production |
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!} |
||||
POSTGRES_USER: ${POSTGRES_USER:-app} |
||||
volumes: |
||||
- database_data:/var/lib/postgresql/data:rw |
||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! |
||||
# - ./docker/db/data:/var/lib/postgresql/data:rw |
||||
###< doctrine/doctrine-bundle ### |
||||
|
||||
volumes: |
||||
###> doctrine/doctrine-bundle ### |
||||
database_data: |
||||
###< doctrine/doctrine-bundle ### |
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
doctrine: |
||||
dbal: |
||||
url: '%env(resolve:DATABASE_URL)%' |
||||
|
||||
# IMPORTANT: You MUST configure your server version, |
||||
# either here or in the DATABASE_URL env var (see .env file) |
||||
#server_version: '16' |
||||
|
||||
profiling_collect_backtrace: '%kernel.debug%' |
||||
use_savepoints: true |
||||
orm: |
||||
auto_generate_proxy_classes: true |
||||
enable_lazy_ghost_objects: true |
||||
report_fields_where_declared: true |
||||
validate_xml_mapping: true |
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware |
||||
auto_mapping: true |
||||
mappings: |
||||
App: |
||||
type: attribute |
||||
is_bundle: false |
||||
dir: '%kernel.project_dir%/src/Entity' |
||||
prefix: 'App\Entity' |
||||
alias: App |
||||
|
||||
when@test: |
||||
doctrine: |
||||
dbal: |
||||
# "TEST_TOKEN" is typically set by ParaTest |
||||
dbname_suffix: '_test%env(default::TEST_TOKEN)%' |
||||
|
||||
when@prod: |
||||
doctrine: |
||||
orm: |
||||
auto_generate_proxy_classes: false |
||||
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' |
||||
query_cache_driver: |
||||
type: pool |
||||
pool: doctrine.system_cache_pool |
||||
result_cache_driver: |
||||
type: pool |
||||
pool: doctrine.result_cache_pool |
||||
|
||||
framework: |
||||
cache: |
||||
pools: |
||||
doctrine.result_cache_pool: |
||||
adapter: cache.app |
||||
doctrine.system_cache_pool: |
||||
adapter: cache.system |
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
doctrine_migrations: |
||||
migrations_paths: |
||||
# namespace is arbitrary but should be different from App\Migrations |
||||
# as migrations classes should NOT be autoloaded |
||||
'DoctrineMigrations': '%kernel.project_dir%/migrations' |
||||
enable_profiler: false |
@ -0,0 +1,141 @@
@@ -0,0 +1,141 @@
|
||||
<?php |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; |
||||
|
||||
use Symfony\Component\Routing\Annotation\Route; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
|
||||
use Doctrine\ORM\EntityManagerInterface; |
||||
|
||||
use App\Entity\Pool; |
||||
|
||||
class CrontabController extends AbstractController |
||||
{ |
||||
#[Route( |
||||
'/crontab/pool', |
||||
name: 'crontab_pool', |
||||
methods: |
||||
[ |
||||
'GET' |
||||
] |
||||
)] |
||||
public function pool( |
||||
Request $request, |
||||
EntityManagerInterface $entity |
||||
): Response |
||||
{ |
||||
// Connect kevacoin |
||||
$client = new \Kevachat\Kevacoin\Client( |
||||
$this->getParameter('app.kevacoin.protocol'), |
||||
$this->getParameter('app.kevacoin.host'), |
||||
$this->getParameter('app.kevacoin.port'), |
||||
$this->getParameter('app.kevacoin.username'), |
||||
$this->getParameter('app.kevacoin.password') |
||||
); |
||||
|
||||
// Get room list |
||||
$rooms = []; |
||||
|
||||
foreach ((array) $client->kevaListNamespaces() as $value) |
||||
{ |
||||
$rooms[$value['namespaceId']] = mb_strtolower($value['displayName']); |
||||
} |
||||
|
||||
// Skip room lock events |
||||
if (empty($rooms)) |
||||
{ |
||||
return new Response(); // @TODO |
||||
} |
||||
|
||||
// Get pending from payment pool |
||||
foreach ($entity->getRepository(Pool::class)->findBy( |
||||
[ |
||||
'sent' => 0, |
||||
'expired' => 0 |
||||
] |
||||
) as $pool) |
||||
{ |
||||
// Payment received, send to blockchain |
||||
if ($client->getReceivedByAddress($pool->getAddress(), $this->getParameter('app.pool.confirmations')) >= $pool->getCost()) |
||||
{ |
||||
// Check physical wallet balance |
||||
if ($client->getBalance() <= $pool->getCost()) |
||||
{ |
||||
break; // @TODO exception |
||||
} |
||||
|
||||
// Is room request |
||||
else if ('_KEVA_NS_' == $pool->getKey()) |
||||
{ |
||||
// Check room name not taken |
||||
if (in_array(mb_strtolower($pool->getValue()), $rooms)) |
||||
{ |
||||
continue; // @TODO exception |
||||
} |
||||
|
||||
// Create new room record |
||||
if ($client->kevaNamespace($pool->getValue())) |
||||
{ |
||||
// Update status |
||||
$pool->setSent( |
||||
time() |
||||
); |
||||
|
||||
$entity->persist( |
||||
$pool |
||||
); |
||||
|
||||
$entity->flush(); |
||||
} |
||||
} |
||||
|
||||
// Is regular key/value request |
||||
else |
||||
{ |
||||
// Check namespace is valid |
||||
if (!isset($rooms[$pool->getNamespace()])) |
||||
{ |
||||
continue; // @TODO exception |
||||
} |
||||
|
||||
if ($client->kevaPut($pool->getNamespace(), $pool->getKey(), $pool->getValue())) |
||||
{ |
||||
// Update status |
||||
$pool->setSent( |
||||
time() |
||||
); |
||||
|
||||
$entity->persist( |
||||
$pool |
||||
); |
||||
|
||||
$entity->flush(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Record expired |
||||
else |
||||
{ |
||||
if ($pool->getTime() + $this->getParameter('app.pool.timeout') >= time()) |
||||
{ |
||||
// Update status |
||||
$pool->setExpired( |
||||
time() |
||||
); |
||||
|
||||
$entity->persist( |
||||
$pool |
||||
); |
||||
|
||||
$entity->flush(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return new Response(); // @TODO |
||||
} |
||||
} |
@ -0,0 +1,141 @@
@@ -0,0 +1,141 @@
|
||||
<?php |
||||
|
||||
namespace App\Entity; |
||||
|
||||
use App\Repository\PoolRepository; |
||||
use Doctrine\DBAL\Types\Types; |
||||
use Doctrine\ORM\Mapping as ORM; |
||||
|
||||
#[ORM\Entity(repositoryClass: PoolRepository::class)] |
||||
class Pool |
||||
{ |
||||
#[ORM\Id] |
||||
#[ORM\GeneratedValue] |
||||
#[ORM\Column] |
||||
private ?int $id = null; |
||||
|
||||
#[ORM\Column] |
||||
private ?int $time = null; |
||||
|
||||
#[ORM\Column] |
||||
private ?int $sent = null; |
||||
|
||||
#[ORM\Column] |
||||
private ?int $expired = null; |
||||
|
||||
#[ORM\Column] |
||||
private ?float $cost = null; |
||||
|
||||
#[ORM\Column(length: 255)] |
||||
private ?string $address = null; |
||||
|
||||
#[ORM\Column(length: 255)] |
||||
private ?string $namespace = null; |
||||
|
||||
#[ORM\Column(length: 255)] |
||||
private ?string $key = null; |
||||
|
||||
#[ORM\Column(type: Types::TEXT)] |
||||
private ?string $value = null; |
||||
|
||||
public function getId(): ?int |
||||
{ |
||||
return $this->id; |
||||
} |
||||
|
||||
public function getTime(): ?int |
||||
{ |
||||
return $this->time; |
||||
} |
||||
|
||||
public function setTime(int $time): static |
||||
{ |
||||
$this->time = $time; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getSent(): ?int |
||||
{ |
||||
return $this->sent; |
||||
} |
||||
|
||||
public function setSent(int $sent): static |
||||
{ |
||||
$this->sent = $sent; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getExpired(): ?int |
||||
{ |
||||
return $this->expired; |
||||
} |
||||
|
||||
public function setExpired(int $expired): static |
||||
{ |
||||
$this->expired = $expired; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getCost(): ?float |
||||
{ |
||||
return $this->cost; |
||||
} |
||||
|
||||
public function setCost(float $cost): static |
||||
{ |
||||
$this->cost = $cost; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getAddress(): ?string |
||||
{ |
||||
return $this->address; |
||||
} |
||||
|
||||
public function setAddress(string $address): static |
||||
{ |
||||
$this->address = $address; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getNamespace(): ?string |
||||
{ |
||||
return $this->namespace; |
||||
} |
||||
|
||||
public function setNamespace(string $namespace): static |
||||
{ |
||||
$this->namespace = $namespace; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getKey(): ?string |
||||
{ |
||||
return $this->key; |
||||
} |
||||
|
||||
public function setKey(string $key): static |
||||
{ |
||||
$this->key = $key; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getValue(): ?string |
||||
{ |
||||
return $this->value; |
||||
} |
||||
|
||||
public function setValue(string $value): static |
||||
{ |
||||
$this->value = $value; |
||||
|
||||
return $this; |
||||
} |
||||
} |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
<?php |
||||
|
||||
namespace App\Repository; |
||||
|
||||
use App\Entity\Pool; |
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; |
||||
use Doctrine\Persistence\ManagerRegistry; |
||||
|
||||
/** |
||||
* @extends ServiceEntityRepository<Pool> |
||||
* |
||||
* @method Pool|null find($id, $lockMode = null, $lockVersion = null) |
||||
* @method Pool|null findOneBy(array $criteria, array $orderBy = null) |
||||
* @method Pool[] findAll() |
||||
* @method Pool[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) |
||||
*/ |
||||
class PoolRepository extends ServiceEntityRepository |
||||
{ |
||||
public function __construct(ManagerRegistry $registry) |
||||
{ |
||||
parent::__construct($registry, Pool::class); |
||||
} |
||||
} |
@ -1,7 +1,13 @@
@@ -1,7 +1,13 @@
|
||||
<form name="room" action="{{ path('room_add', { mode : request.get('mode') }) }}" method="post"> |
||||
<form name="room" action="{{ path('room_add', { mode : request.get('mode') }) }}" method="post"> |
||||
{% if request.get('error') %} |
||||
<output name="error" for="form-room-name">{{ request.get('error') }}</output> |
||||
{% endif %} |
||||
{% if request.get('warning') %} |
||||
<output name="warning" for="form-room-name">{{ request.get('warning') }}</output> |
||||
{% endif %} |
||||
<input type="text" name="name" id="form-room-name" value="{{ request.get('name') }}" placeholder="{{ 'enter new room name...' | trans }}" /> |
||||
<button type="submit">{{ 'add' | trans }}</button> |
||||
</form> |
||||
{% if cost %} |
||||
<span>{{ 'cost: %s KVA' | format(cost) | trans }}</span> |
||||
{% endif %} |
||||
</form> |
Loading…
Reference in new issue