Add base records routes
This commit is contained in:
parent
4e6d4f396b
commit
b90a0cd63a
|
@ -0,0 +1,33 @@
|
|||
# In all environments, the following files are loaded if they exist,
|
||||
# the latter taking precedence over the former:
|
||||
#
|
||||
# * .env contains default values for the environment variables needed by the app
|
||||
# * .env.local uncommitted file with local overrides
|
||||
# * .env.$APP_ENV committed environment-specific defaults
|
||||
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||
#
|
||||
# Real environment variables win over .env files.
|
||||
#
|
||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||
# https://symfony.com/doc/current/configuration/secrets.html
|
||||
#
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=8bd3643031a08d0cd34e6fd3f680fb22
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||
#
|
||||
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8&charset=utf8mb4"
|
||||
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14&charset=utf8"
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
### records folder
|
||||
RECORDS_DIR=%kernel.project_dir%/../var/chunks # adapt to your needs
|
||||
###
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
###> symfony/framework-bundle ###
|
||||
!.env
|
||||
/.env.local
|
||||
/.env.local.php
|
||||
/.env.*.local
|
||||
|
|
|
@ -12,9 +12,13 @@ import './styles/menu.css';
|
|||
// start the Stimulus application
|
||||
import './bootstrap';
|
||||
|
||||
import './utils/spectro';
|
||||
import './utils/date';
|
||||
import feather from 'feather-icons';
|
||||
feather.replace();
|
||||
|
||||
document.getElementsByClassName('prevent').map(
|
||||
(e) => e.addEventListener('click', (e) => e.preventDefault())
|
||||
);
|
||||
try {
|
||||
document.getElementsByClassName('prevent').map(
|
||||
(e) => e.addEventListener('click', (e) => e.preventDefault())
|
||||
);
|
||||
} catch {
|
||||
console.debug('no prevent class found');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
(function() {
|
||||
try {
|
||||
let delete_buttons = document.getElementsByClassName("delete-button");
|
||||
} catch {
|
||||
console.debug("no delete buttons found");
|
||||
}
|
||||
})();
|
|
@ -164,6 +164,12 @@ footer a:hover {
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
li, td {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
td
|
||||
|
||||
/* .dropdown-button:hover {
|
||||
background-color: #900;
|
||||
color: white
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
let date_input;
|
||||
let endpoint;
|
||||
|
||||
let date_input = document.querySelector("input[type='date']");
|
||||
let next_date_button = document.getElementsByClassName("next-date-button")[0];
|
||||
let previous_date_button = document.getElementsByClassName("previous-date-button")[0];
|
||||
try {
|
||||
date_input = document.querySelector(".date-selector input[type='date']");
|
||||
let next_date_button = document.getElementsByClassName("next-date-button")[0];
|
||||
let previous_date_button = document.getElementsByClassName("previous-date-button")[0];
|
||||
endpoint = document.querySelector(".date-selector a").href.split("/")[3];
|
||||
|
||||
next_date_button.addEventListener("click", next_date);
|
||||
previous_date_button.addEventListener("click", previous_date);
|
||||
} catch {
|
||||
console.debug("no date input found");
|
||||
}
|
||||
|
||||
function next_date() {
|
||||
let date = new Date(date_input.value);
|
||||
|
@ -20,8 +30,5 @@ function previous_date() {
|
|||
function update_date_link() {
|
||||
let date = new Date(date_input.value);
|
||||
let date_link = document.querySelector(".date-selector a");
|
||||
date_link.href = `/today/${date.toISOString().split('T')[0]}/species`;
|
||||
date_link.href = `/${endpoint}/${date.toISOString().split('T')[0]}/`;
|
||||
}
|
||||
|
||||
next_date_button.addEventListener("click", next_date);
|
||||
previous_date_button.addEventListener("click", previous_date);
|
|
@ -15,7 +15,7 @@ try {
|
|||
initialize();
|
||||
})
|
||||
} catch {
|
||||
console.log("spectro not found");
|
||||
console.debug("spectro not found");
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
app.records_dir: '%env(resolve:RECORDS_DIR)%'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
|
|
|
@ -14,5 +14,8 @@
|
|||
"dev": "encore dev",
|
||||
"watch": "encore dev --watch",
|
||||
"build": "encore production --progress"
|
||||
},
|
||||
"dependencies": {
|
||||
"feather-icons": "^4.29.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
class RecordsController extends AbstractController
|
||||
{
|
||||
private Connection $connection;
|
||||
|
||||
/**
|
||||
* @Route("/records/{date}", name="records_index")
|
||||
*/
|
||||
public function records_index($date="now")
|
||||
{
|
||||
if ($date == "now") {
|
||||
$date = date("Y-m-d");
|
||||
}
|
||||
$records = $this->list_records();
|
||||
$records = $this->only_on($date, $records);
|
||||
return $this->render('records/index.html.twig', [
|
||||
'records' => $records,
|
||||
'date' => $date,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/records/remove/{basename}", name="record_remove")
|
||||
*/
|
||||
public function remove_record($basename)
|
||||
{
|
||||
$this->remove_record_by_basename($basename);
|
||||
return $this->redirectToRoute('records_index');
|
||||
}
|
||||
|
||||
private function list_records()
|
||||
{
|
||||
$records_path = $this->getParameter('app.records_dir')."/out/*.wav";
|
||||
$records = glob($records_path);
|
||||
$records = array_map(function($record) {
|
||||
$record = basename($record);
|
||||
return $record;
|
||||
}, $records);
|
||||
return $records;
|
||||
}
|
||||
|
||||
private function get_record_date($record_path)
|
||||
{
|
||||
$record_basename = basename($record_path);
|
||||
$record_date = explode("_", explode(".", $record_basename)[0])[1];
|
||||
$year = substr($record_date, 0, 4);
|
||||
$month = substr($record_date, 4, 2);
|
||||
$day = substr($record_date, 6, 2);
|
||||
$date = "$year-$month-$day";
|
||||
return $date;
|
||||
}
|
||||
|
||||
private function only_on($date, $records) {
|
||||
$filtered_records = array_filter($records, function($record) use ($date) {
|
||||
return $this->get_record_date($record) == $date;
|
||||
});
|
||||
return $filtered_records;
|
||||
}
|
||||
|
||||
private function remove_record_by_basename($basename) {
|
||||
$record_path = $this->getParameter('app.records_dir')."/out/$basename";
|
||||
unlink($record_path);
|
||||
unlink($record_path.".d/model.out.csv");
|
||||
rmdir($this->getParameter('app.records_dir')."/out/$basename.d");
|
||||
}
|
||||
}
|
|
@ -119,7 +119,8 @@ class TodayController extends AbstractController
|
|||
$stat = $result->fetchAllAssociative();
|
||||
$sql = "SELECT * FROM `observation`
|
||||
WHERE `taxon_id` = :id
|
||||
AND strftime('%Y-%m-%d', `observation`.`date`) = :date";
|
||||
AND strftime('%Y-%m-%d', `observation`.`date`) = :date
|
||||
ORDER BY `observation`.`date` ASC";
|
||||
$stmt = $this->connection->prepare($sql);
|
||||
$stmt->bindValue(':id', $id);
|
||||
$stmt->bindValue(':date', $date);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ "Records" }}</h2>
|
||||
{% set endpoint = "records" %}
|
||||
{% include "utils/calendar.html.twig" %}
|
||||
{% if records is defined and records | length > 0 %}
|
||||
<ul>
|
||||
{% for record in records %}
|
||||
<li>{{ record }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -10,7 +10,8 @@
|
|||
{{ date | format_datetime("full", "none") }}
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% include "today/calendar.html.twig" %}
|
||||
{% set endpoint = "today" %}
|
||||
{% include "utils/calendar.html.twig" %}
|
||||
{# Display a list of records if any, else, print message #}
|
||||
{% if results is defined and results | length > 0 %}
|
||||
<ul>
|
||||
|
|
|
@ -2,36 +2,36 @@
|
|||
|
||||
{% block content %}
|
||||
{% if results is defined and results | length > 0 %}
|
||||
{% set taxon = results["taxon"] %}
|
||||
{% set taxon = results.taxon %}
|
||||
<h2>
|
||||
{% set today = "now" | date("Y-m-d") %}
|
||||
{% if today == date %}
|
||||
{{ "Today's contact for" | trans }}
|
||||
{{ "Today's contacts for" | trans }}
|
||||
{% else %}
|
||||
{{ "Contact on " | trans }}
|
||||
{{ "Contacts on " | trans }}
|
||||
{{ date | format_datetime("full", "none") }}
|
||||
{{ " for " | trans }}
|
||||
{% endif %}
|
||||
<span class="scientific-name">
|
||||
{{ taxon["scientific_name"] }}
|
||||
{{ taxon.scientific_name }}
|
||||
</span>
|
||||
(<span class="common-name">
|
||||
{{ taxon["common_name"] }}
|
||||
{{ taxon.common_name }}
|
||||
</span>)
|
||||
</h2>
|
||||
<div class="stats">
|
||||
{% set stat = results["stat"][0] %}
|
||||
{% set stat = results.stat[0] %}
|
||||
<h3>{{ "Stats" | trans }}</h3>
|
||||
<div class="contact-count">
|
||||
{{ "Contact count:" | trans }}
|
||||
<span class="counter">{{ stat["contact_count"] }}</span>
|
||||
<span class="counter">{{ stat.contact_count }}</span>
|
||||
</div>
|
||||
<div class="contact-confidence">
|
||||
{{ "Max confidence" | trans }}
|
||||
<span class="value">{{ stat["max_confidence"] }}</span>
|
||||
<span class="value">{{ stat.max_confidence }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% set records = results["records"] %}
|
||||
{% set records = results.records %}
|
||||
<div class="records">
|
||||
<h3>{{ "Contact records" | trans }}</h3>
|
||||
{% if records is defined and records | length > 0 %}
|
||||
|
@ -47,17 +47,15 @@
|
|||
{% for record in records %}
|
||||
<tr>
|
||||
<td>
|
||||
<a title="{{ "Download audio file" | trans }}" href="/media/records/{{ record['audio_file'] }}">
|
||||
{{ record["audio_file"] }}
|
||||
<a title="{{ "Download audio file" | trans }}" href="/media/records/{{ record.audio_file }}">
|
||||
{{ record.audio_file }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ record["date"] | date("H:m") }}</td>
|
||||
<td>{{ record["confidence"] }}</td>
|
||||
<td>{{ record.date | date("H:m") }}</td>
|
||||
<td>{{ record.confidence }}</td>
|
||||
<td>
|
||||
<audio controls>
|
||||
<source src="/media/records/{{ record['audio_file'] }}" type="audio/wav">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
{% include "utils/player.html.twig" with { "file": record.audio_file } only %}
|
||||
<button class="delete" value="{{ record.audio_file }}"><i data-feather="trash-2"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<div class="date-selector container row">
|
||||
<label for="date ">{{ "Date" | trans }}</label>
|
||||
<label for="date">{{ "Date" | trans }}</label>
|
||||
<button class="previous-date-button button"><</button>
|
||||
<input type="date" id="date" name="date" value="{{ date ? date : "now" | date("Y-m-d") }}" placeholder="YYYY-MM-DD" required pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" title="{{ "Enter a date in this format YYYY-MM-DD" | trans }}"/>
|
||||
<button class="next-date-button button prevent">></button>
|
||||
<a href="/today/{{ date ? date : " now" | date(" y-m-d") }}/species" class="button main">{{ "Go" | trans }}</a>
|
||||
<a href="/{{ endpoint }}/{{ date ? date : " now" | date("Y-m-d") }}/" class="button main">{{ "Go" | trans }}</a>
|
||||
</div>
|
||||
|
||||
{{ encore_entry_script_tags('date') }}
|
|
@ -0,0 +1,3 @@
|
|||
<audio preload="none" controls>
|
||||
<source src="/media/records/{{ file }}">
|
||||
</audio>
|
|
@ -22,6 +22,9 @@ Encore
|
|||
*/
|
||||
.addEntry('app', './assets/app.js')
|
||||
|
||||
.addEntry('spectro', './assets/utils/spectro.js')
|
||||
.addEntry('date', './assets/utils/date.js')
|
||||
|
||||
// enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js)
|
||||
.enableStimulusBridge('./assets/controllers.json')
|
||||
|
||||
|
|
|
@ -1660,6 +1660,11 @@ chrome-trace-event@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
|
||||
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
|
||||
|
||||
classnames@^2.2.5:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
||||
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
||||
|
||||
clean-webpack-plugin@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729"
|
||||
|
@ -1797,7 +1802,7 @@ core-js-compat@^3.21.0, core-js-compat@^3.22.1:
|
|||
browserslist "^4.21.3"
|
||||
semver "7.0.0"
|
||||
|
||||
core-js@^3.23.0:
|
||||
core-js@^3.1.3, core-js@^3.23.0:
|
||||
version "3.24.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f"
|
||||
integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==
|
||||
|
@ -2249,6 +2254,14 @@ faye-websocket@^0.11.3:
|
|||
dependencies:
|
||||
websocket-driver ">=0.5.1"
|
||||
|
||||
feather-icons@^4.29.0:
|
||||
version "4.29.0"
|
||||
resolved "https://registry.yarnpkg.com/feather-icons/-/feather-icons-4.29.0.tgz#4e40e3cbb7bf359ffbbf700edbebdde4e4a74ab6"
|
||||
integrity sha512-Y7VqN9FYb8KdaSF0qD1081HCkm0v4Eq/fpfQYQnubpqi0hXx14k+gF9iqtRys1SIcTEi97xDi/fmsPFZ8xo0GQ==
|
||||
dependencies:
|
||||
classnames "^2.2.5"
|
||||
core-js "^3.1.3"
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||
|
|
Loading…
Reference in New Issue