mirror of https://github.com/kevachat/webapp.git
ghost
9 months ago
25 changed files with 895 additions and 36 deletions
@ -0,0 +1,8 @@ |
|||||||
|
version: '3' |
||||||
|
|
||||||
|
services: |
||||||
|
###> doctrine/doctrine-bundle ### |
||||||
|
database: |
||||||
|
ports: |
||||||
|
- "5432" |
||||||
|
###< doctrine/doctrine-bundle ### |
@ -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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
<?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 @@ |
|||||||
<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') %} |
{% if request.get('error') %} |
||||||
<output name="error" for="form-room-name">{{ request.get('error') }}</output> |
<output name="error" for="form-room-name">{{ request.get('error') }}</output> |
||||||
{% endif %} |
{% endif %} |
||||||
<input type="text" name="name" id="form-room-name" value="{{ request.get('name') }}" placeholder="{{ 'enter new room name...' | trans }}" /> |
{% if request.get('warning') %} |
||||||
<button type="submit">{{ 'add' | trans }}</button> |
<output name="warning" for="form-room-name">{{ request.get('warning') }}</output> |
||||||
</form> |
{% 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> |
||||||
|
{% if cost %} |
||||||
|
<span>{{ 'cost: %s KVA' | format(cost) | trans }}</span> |
||||||
|
{% endif %} |
||||||
|
</form> |
Loading…
Reference in new issue