Commit fe1f3c5c authored by Clouard Regis's avatar Clouard Regis
Browse files

Refactored courses

parent 591e039d
......@@ -13,7 +13,9 @@
Une fois le projet cloné, il faut :
- faire `composer install` pour installer tous les bundles.
- installer une base
symfony server:start --dir=site-vikazimut/public
```
symfony server:start --dir=site-vikazimut/public
```
### Installer la base de données mysql
......@@ -51,7 +53,9 @@ Vérifier la taille maximale des fichiers téléversables (eg. dans php.ini ou c
Le fichier `composer.json` référence les paquets utilisés par le projet avec leur numéro de version.
Pour changer la version de Symfony, il faut mettre à jour la version des paquets Symfony, puis lancer la commande :
```composer update -with-all-dependencies```
```
php7.4-cli composer.phar update –no-dev --with-all-dependencies
```
### Déploiement en production
......
......@@ -66,7 +66,7 @@ class EventController extends AbstractController
public function create_event(Request $request): Response
{
$event = new Event();
$event->setCreator((User::class)($this->security->getUser()));
$event->setCreator($this->security->getUser());
$eventForm = $this->createForm(EventType::class, $event);
$eventForm->handleRequest($request);
......@@ -91,7 +91,7 @@ class EventController extends AbstractController
*/
public function details(int $id, Request $request): Response
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$event = $this->getDoctrine()->getRepository(Event::class)->find($id);
$formsView = [];
$participants = $event->getParticipants();
......@@ -170,7 +170,7 @@ class EventController extends AbstractController
*/
public function updateEvent($id): RedirectResponse
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$event = $this->getDoctrine()->getRepository(Event::class)->find($id);
if ($event != null && (in_array($event, $user->getEvents()->toArray()) || in_array('ROLE_ADMIN', $user->getRoles()))) {
$event->update($this->getDoctrine()->getManager(), $this->getDoctrine()->getRepository(ParticipantMakeEventCourse::class));
......@@ -188,7 +188,7 @@ class EventController extends AbstractController
*/
public function deleteEvent($id): RedirectResponse
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$entityManager = $this->getDoctrine()->getManager();
$event = $this->getDoctrine()->getRepository(Event::class)->find($id);
if ($event != null && (in_array($event, $user->getEvents()->toArray()) || in_array('ROLE_ADMIN', $user->getRoles()))) {
......@@ -243,7 +243,7 @@ class EventController extends AbstractController
*/
public function deleteParticipant(int $idEvent, int $id): RedirectResponse
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$entityManager = $this->getDoctrine()->getManager();
$participant = $this->getDoctrine()->getRepository(Participant::class)->find($id);
$event = $this->getDoctrine()->getRepository(Event::class)->find($idEvent);
......@@ -310,7 +310,7 @@ class EventController extends AbstractController
*/
public function deleteEventCourse(int $idEvent, int $id): RedirectResponse
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$entityManager = $this->getDoctrine()->getManager();
$eventCourse = $this->getDoctrine()->getRepository(EventCourse::class)->find($id);
$event = $this->getDoctrine()->getRepository(Event::class)->find($idEvent);
......
......@@ -116,7 +116,7 @@ class PlannerController extends AbstractController
*/
public function missing_control_point($id): Response
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$course = $this->getDoctrine()->getRepository(Course::class)->find($id);
if (in_array($course, $user->getCourses()->toArray()) || in_array('ROLE_ADMIN', $user->getRoles())) {
$controlPoints = $course->getMissingControlPoints();
......@@ -137,7 +137,7 @@ class PlannerController extends AbstractController
*/
public function delete($id): RedirectResponse
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$entityManager = $this->getDoctrine()->getManager();
$course = $this->getDoctrine()->getRepository(Course::class)->find($id);
if ($course != null && (in_array($course, $user->getCourses()->toArray()) || in_array('ROLE_ADMIN', $user->getRoles()))) {
......@@ -154,7 +154,7 @@ class PlannerController extends AbstractController
*/
public function delete_missing_control_point($id): RedirectResponse
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$entityManager = $this->getDoctrine()->getManager();
$controlPoint = $this->getDoctrine()->getRepository(MissingControlPoint::class)->find($id);
$course = $controlPoint->getCourse();
......@@ -173,7 +173,7 @@ class PlannerController extends AbstractController
*/
public function preview($id): Response
{
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$course = $this->getDoctrine()->getRepository(Course::class)->find($id);
if (in_array($course, $user->getCourses()->toArray()) || in_array('ROLE_ADMIN', $user->getRoles())) {
return $this->render(
......@@ -234,7 +234,7 @@ class PlannerController extends AbstractController
$success = "";
$response = new JsonResponse();
foreach ($request->files->all() as $file) {
$user = (User::class)($this->security->getUser());
$user = $this->security->getUser();
$success = FileUploader::uploadFile($file, $user->getId());
if (!$success) {
return $response->fromJsonString($success);
......
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210514132848 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('DROP TABLE reset_password_request');
$this->addSql('ALTER TABLE course ADD club VARCHAR(30) DEFAULT NULL, CHANGE printable printable TINYINT(1) NOT NULL');
$this->addSql('ALTER TABLE track CHANGE imported imported TINYINT(1) NOT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('CREATE TABLE reset_password_request (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, selector VARCHAR(20) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, hashed_token VARCHAR(100) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, requested_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', expires_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_7CE748AA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
$this->addSql('ALTER TABLE reset_password_request ADD CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE NO ACTION');
$this->addSql('ALTER TABLE course DROP club, CHANGE printable printable TINYINT(1) DEFAULT \'0\' NOT NULL');
$this->addSql('ALTER TABLE track CHANGE imported imported TINYINT(1) DEFAULT \'0\' NOT NULL');
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210527125129 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('ALTER TABLE participant_make_event_course ADD pm_penalty_manually_set TINYINT(1) DEFAULT \'0\' NOT NULL, ADD ot_penalty_manually_set TINYINT(1) DEFAULT \'0\' NOT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('ALTER TABLE participant_make_event_course DROP pm_penalty_manually_set, DROP ot_penalty_manually_set');
}
}
......@@ -20,7 +20,6 @@ use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticato
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
// TODO
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
......@@ -40,13 +39,12 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
public function supports(Request $request): bool
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
return self::LOGIN_ROUTE === $request->attributes->get('_route') && $request->isMethod('POST');
}
public function getCredentials(Request $request)
public function getCredentials(Request $request): array
{
$credentials = [
'username' => $request->request->get('username'),
......@@ -67,17 +65,15 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
// TODO catch ???
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException("Le compte n'existe pas.");
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
public function checkCredentials($credentials, UserInterface $user): bool
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
......@@ -90,7 +86,7 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): RedirectResponse
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
......@@ -99,7 +95,7 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
return new RedirectResponse($this->urlGenerator->generate('your_courses'));
}
protected function getLoginUrl()
protected function getLoginUrl(): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
......
......@@ -19,6 +19,8 @@
}
</style>
{% block stylesheets %}{% endblock %}
<script src="{{ asset('/public/javascript/jquery-3.5.1.slim.min.js') }}"></script>
<script src="{{ asset('/public/bootstrap-4.5.2/js/bootstrap.min.js') }}"></script>
<script>
function toggleSidebar(){
let sidebar = document.getElementById("nav-sidebar");
......@@ -143,8 +145,6 @@
</footer>
{% block javascripts %}
<script src="{{ asset('/public/javascript/jquery-3.5.1.slim.min.js') }}"></script>
<script src="{{ asset('/public/bootstrap-4.5.2/js/bootstrap.min.js') }}"></script>
{% endblock %}
</body>
......
......@@ -58,7 +58,15 @@
function switchMapDisplay() { // TODO new
let hideButton = document.getElementById("hide-map");
let showButton = document.getElementById("show-map");
overlayOpacity === 100 ? (overlayOpacity = 0, hideButton.style.display = "block", showButton.style.display = "none") : (overlayOpacity = 100, hideButton.style.display = "none", showButton.style.display = "block");
if (overlayOpacity === 100) {
overlayOpacity = 0;
hideButton.style.display = "block";
showButton.style.display = "none";
} else {
overlayOpacity = 100;
hideButton.style.display = "none";
showButton.style.display = "block";
}
overlay.setOpacity(overlayOpacity);
}
......@@ -98,17 +106,17 @@
<div id="description-tab" class="tab-content list-group">
<div class="d-flex">
<div class="">
<p>{% trans %} course.description.author {% endtrans %} : {{ creator }}</p>
<p>{% trans %}course.description.author{% endtrans %} {{ creator }}</p>
{% if club != null %}
<p>{% trans %} course.description.club.name {% endtrans %} : {{ club }}</p>
<p>{% trans %}course.description.club.name{% endtrans %} {{ club }}</p>
{% endif %}
{% if app.request.locale == 'fr' %}
<p>{% trans %} course.description.date {% endtrans %} : {{ day }}/{{ month }}/{{ year }}</p>
<p>{% trans %}course.description.date{% endtrans %} {{ day }}/{{ month }}/{{ year }}</p>
{% else %}
<p>{% trans %} course.description.date {% endtrans %} : {{ month }}/{{ day }}/{{ year }}</p>
<p>{% trans %}course.description.date{% endtrans %} {{ month }}/{{ day }}/{{ year }}</p>
{% endif %}
<p>{% trans %} course.description.control.point.number {% endtrans %} : {{ control_point_number }}</p>
<p>{% trans %} course.description.length {% endtrans %} : {{ length }} m</p>
<p>{% trans %}course.description.control.point.number{% endtrans %} {{ control_point_number }}</p>
<p>{% trans %}course.description.length{% endtrans %} {{ length }} m</p>
</div>
</div>
</div>
......
......@@ -49,16 +49,16 @@
<script>
let translations = {
'start' : '{{ 'timeSheet.start' | trans | escape('js') }}',
'finish' : '{{ 'timeSheet.finish' | trans | escape('js') }}',
'duration' : '{{ 'timeSheet.duration' | trans | escape('js') }}',
'distance' : '{{ 'timeSheet.distance' | trans | escape('js') }}',
'controlPoint' : '{{ 'timeSheet.control.point' | trans | escape('js') }}',
'length' : '{{ 'timeSheet.length' | trans | escape('js') }}',
'RK' : '{{ 'timeSheet.RK' | trans | escape('js') }}',
'total' : '{{ 'timeSheet.total' | trans | escape('js') }}',
'mean' : '{{ 'timeSheet.mean' | trans | escape('js') }}',
'speed' : '{{ 'timeSheet.speed' | trans | escape('js') }}',
'start': '{{ 'timeSheet.start' | trans | escape('js') }}',
'finish': '{{ 'timeSheet.finish' | trans | escape('js') }}',
'duration': '{{ 'timeSheet.duration' | trans | escape('js') }}',
'distance': '{{ 'timeSheet.distance' | trans | escape('js') }}',
'controlPoint': '{{ 'timeSheet.control.point' | trans | escape('js') }}',
'length': '{{ 'timeSheet.length' | trans | escape('js') }}',
'RK': '{{ 'timeSheet.RK' | trans | escape('js') }}',
'total': '{{ 'timeSheet.total' | trans | escape('js') }}',
'mean': '{{ 'timeSheet.mean' | trans | escape('js') }}',
'speed': '{{ 'timeSheet.speed' | trans | escape('js') }}',
}
const colorPicker = new ColorPicker();
const tableEnable = false;
......@@ -171,19 +171,16 @@
xhr.send();
});
</script>
{% endblock %}
{% block body %}
<div class="container-fluid" style="margin-top:20pt">
<div class="row align-items-start" style="">
<div id="tracks" class="col"
style="padding-top:10px;padding-bottom:10px; max-height: 100%; max-width: 25em;min-width: 18em">
<div id="tracks" class="col" style="padding-top:10px;padding-bottom:10px; max-height: 100%; max-width: 25em;min-width: 18em">
<h3 class="text-center">{{ name }}</h3>
<div id="track-form" hidden>
<button class="btn btn-primary visible-xs dropdown-toggle" type="button" data-toggle="collapse"
data-target="#side-menu-collapse" aria-expanded="false" aria-controls="collapseList"
style="width: 100%;">
<button class="btn btn-primary visible-xs dropdown-toggle" type="button" data-toggle="collapse" data-target="#side-menu-collapse" aria-expanded="true" aria-controls="side-menu-collapse" style="width: 100%;">
{% trans %}track.gpstracks{% endtrans %}
</button>
<div id="side-menu-collapse">
......@@ -196,14 +193,10 @@
<div class="col" style="width:100%">
<div class="tab">
<button class="tab-links" onclick="openTab('tab1', 'map-tab')"
id="tab1">{% trans %} track.map {% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab2', 'times-tab')"
id="tab2">{% trans %} track.time {% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab3', 'import-tab')"
id="tab3">{% trans %} track.import {% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab4', 'files-tab')"
id="tab4">{% trans %} track.export {% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab1', 'map-tab')" id="tab1">{% trans %}track.map{% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab2', 'times-tab')" id="tab2">{% trans %}track.time{% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab3', 'import-tab')" id="tab3">{% trans %}track.import{% endtrans %}</button>
<button class="tab-links" onclick="openTab('tab4', 'files-tab')" id="tab4">{% trans %}track.export{% endtrans %}</button>
</div>
<!-- Tab content -->
......@@ -211,13 +204,15 @@
<button class="btn btn-primary" id="show-map" onclick="switchMapDisplay(overlay, 100)" style="position: absolute; z-index: 9999; top: 60px; right: 35px">{% trans %} course.description.mask.map {% endtrans %}</button>
<button class="btn btn-primary" id="hide-map" onclick="switchMapDisplay(overlay, 0)" style="display:none; position: absolute; z-index: 9999; top: 60px; right: 35px">{% trans %} course.description.show.map {% endtrans %}</button>
<div id="map-div" style="min-width: 300px"></div>
<p id="map-not-found" class="alert alert-danger"
style="display : none">{% trans %}course.error.map.not.found{% endtrans %}</p>
<p id="map-not-found" class="alert alert-danger" style="display : none">{% trans %}course.error.map.not.found{% endtrans %}</p>
</div>
<div id="times-tab" class="tab-content">
<div id="time-sheet-div" style="min-width: 300px"></div>
</div>
<div id="files-tab" class="tab-content" style="min-width: 300px">
<div class="panel-heading">
<h3 class="panel-title">{% trans %}track.export.title{% endtrans %}</h3>
</div>
</div>
{% form_theme form 'bootstrap_4_layout.html.twig' %}
<div id="import-tab" class="tab-content">
......@@ -257,6 +252,7 @@
</div>
</div>
</div>
<script>
function openTab(tabTitle, tabId) {
let i, tabContent, tabLinks;
......
......@@ -225,19 +225,19 @@
<div class="container">
<div class="row">
<div class="col-md-4">
<img src="{{ asset('/public/images/vikazim_logo.png') }}" height="130"/>
<img src="{{ asset('/public/images/vikazim_logo.png') }}" alt="logo Vikazim" height="130"/>
<h3>{% trans %}homepage.vikazim.title{% endtrans %}</h3>
<p>{% trans %}homepage.vikazim.description{% endtrans %}</p>
<p><a class="btn btn-secondary" href="https://vikazim.fr/" role="button">{% trans %}read.more{% endtrans %} &raquo;</a></p>
</div>
<div class="col-md-4">
<img src="{{ asset('/public/images/ensi_logo.png') }}" height="130"/>
<img src="{{ asset('/public/images/ensi_logo.png') }}" height="130" alt="logo ENSICAEN"/>
<h3>{% trans %}homepage.ensicaen.title{% endtrans %}</h3>
<p>{% trans %}homepage.ensicaen.description{% endtrans %}</p>
<p><a class="btn btn-secondary" href="https://www.ensicaen.fr/formations/ingenieur-informatique/" role="button">{% trans %}read.more{% endtrans %} &raquo;</a></p>
</div>
<div class="col-md-4">
<img src="{{ asset('/public/images/unicaen_logo.png') }}" height="130"/>
<img src="{{ asset('/public/images/unicaen_logo.png') }}" height="130" alt="logo UNICAEN"/>
<h3>{% trans %}homepage.unicaen.title{% endtrans %}</h3>
<p>{% trans %}homepage.unicaen.description{% endtrans %}</p>
<p><a class="btn btn-secondary" href="https://uniform.unicaen.fr/catalogue/formation/licences/5744-licence-informatique" role="button">{% trans %}read.more{% endtrans %} &raquo;</a></p>
......
......@@ -95,7 +95,7 @@
</trans-unit>
<trans-unit id="DnXGH9U" resname="admin_list_planners.info">
<source>admin_list_planners.info</source>
<target>User Info</target>
<target>User Information</target>
</trans-unit>
<trans-unit id="jL_5xLb" resname="add.user">
<source>add.user</source>
......@@ -183,7 +183,7 @@
</trans-unit>
<trans-unit id="1TrEmbU" resname="missing.control_point.title">
<source>missing.control_point.title</source>
<target>Missing control point</target>
<target>Missing punches</target>
</trans-unit>
<trans-unit id="YZdZVQP" resname="delete">
<source>delete</source>
......@@ -207,7 +207,7 @@
</trans-unit>
<trans-unit id="0evx.sZ" resname="show_course.control_point_number">
<source>show_course.control_point_number</source>
<target>Missing control points : %nb%</target>
<target>Missing punches : %nb%</target>
</trans-unit>
<trans-unit id="OW0jvjK" resname="show_course.delete">
<source>show_course.delete</source>
......@@ -387,11 +387,11 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="lfAvSAq" resname="course.description.date">
<source>course.description.date</source>
<target>Date (US format)</target>
<target>Creation Date:</target>
</trans-unit>
<trans-unit id="iTBKi17" resname="course.description.length">
<source>course.description.length</source>
<target>Theoretical Length</target>
<target>Theoretical Length: </target>
</trans-unit>
<trans-unit id="K7VqOZY" resname="course.description.show.map">
<source>course.description.show.map</source>
......@@ -415,11 +415,15 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="CIL.G4d" resname="course.description.author">
<source>course.description.author</source>
<target>Creator</target>
<target>Creator:</target>
</trans-unit>
<trans-unit id="xRNsMjX" resname="course.description.club.name">
<source>course.description.club.name</source>
<target>Club or Organization:</target>
</trans-unit>
<trans-unit id="3ioMREz" resname="course.description.control.point.number">
<source>course.description.control.point.number</source>
<target>Control points</target>
<target>Total Control Points:</target>
</trans-unit>
<trans-unit id="Mbl.BQn" resname="homepage.uses.conditions.html">
<source>homepage.uses.conditions.html</source>
......@@ -455,7 +459,11 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="VyusrBP" resname="track.import.title">
<source>track.import.title</source>
<target>Track import from GPX file</target>
<target>GPX track import</target>
</trans-unit>
<trans-unit id="9u5cjY7" resname="track.export.title">
<source>track.export.title</source>
<target>GPX track export</target>
</trans-unit>
<trans-unit id="KN2Pte_" resname="import.gpx.nickname">
<source>import.gpx.nickname</source>
......@@ -467,11 +475,11 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="twAmtkh" resname="import.gpx.route.preset">
<source>import.gpx.route.preset</source>
<target>preset</target>
<target>Preset order</target>
</trans-unit>
<trans-unit id="NwT62T6" resname="import.gpx.route.free">
<source>import.gpx.route.free</source>
<target>free</target>
<target>Free order</target>
</trans-unit>
<trans-unit id=".Ag8W_." resname="import.gpx.file">
<source>import.gpx.file</source>
......@@ -529,10 +537,6 @@ such as orienteering, multisport orienteering, trails...</target>
<source>track.import.success</source>
<target>Successfully imported</target>
</trans-unit>
<trans-unit id="xRNsMjX" resname="course.description.club.name">
<source>course.description.club.name</source>
<target>Club</target>
</trans-unit>
<trans-unit id="zizLSLK" resname="course.club.name">
<source>course.club.name</source>
<target>Club name</target>
......@@ -655,11 +659,11 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="2Z2rBfK" resname="my_event_details.courses_table.over_time_penalty">
<source>my_event_details.courses_table.over_time_penalty</source>
<target>Penalty per minute exceeded in points</target>
<target>Minute exceeded penalty in points</target>
</trans-unit>
<trans-unit id="3Wlf2.i" resname="my_event_details.courses_table.PM_penalty">
<source>my_event_details.courses_table.PM_penalty</source>
<target>PM penalty in points</target>
<target>Missing punch penalty in points</target>
</trans-unit>
<trans-unit id="fwozrXx" resname="my_event_details.courses">
<source>my_event_details.courses</source>
......@@ -703,7 +707,7 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="ulQTd7h" resname="my_event_details.imposed">
<source>my_event_details.imposed</source>
<target>Imposed</target>
<target>Preset</target>
</trans-unit>
<trans-unit id="shDHoab" resname="eventslist.title">
<source>eventslist.title</source>
......@@ -767,7 +771,7 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="g8XJIb5" resname="event.info.courses_table.PM_penalty">
<source>event.info.courses_table.PM_penalty</source>
<target>PM penalty</target>
<target>Missing punch penalty</target>
</trans-unit>
<trans-unit id="ZDI79ZV" resname="event.info.courses_table.over_time_penalty">
<source>event.info.courses_table.over_time_penalty</source>
......@@ -803,7 +807,7 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="unquYr4" resname="form.eventCourse.imposed">
<source>form.eventCourse.imposed</source>
<target>Imposed</target>
<target>Preset</target>
</trans-unit>
<trans-unit id="v8oy6oh" resname="form.eventCourse.free">
<source>form.eventCourse.free</source>
......@@ -1087,19 +1091,19 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="x5C6wHW" resname="event.info.courses_table.PM_penalty_sec">
<source>event.info.courses_table.PM_penalty_sec</source>
<target>PM penalty in second</target>
<target>Missing punch penalty in seconds</target>
</trans-unit>
<trans-unit id="QQddspD" resname="event.info.courses_table.over_time_penalty_sec">
<source>event.info.courses_table.over_time_penalty_sec</source>
<target>Penalty per minute exceeded in second</target>
<target>Penalty per minute exceeded in seconds</target>
</trans-unit>
<trans-unit id="eAcXosP" resname="my_event_details.courses_table.PM_penalty_sec">
<source>my_event_details.courses_table.PM_penalty_sec</source>
<target>PM penalty in second</target>
<target>PM penalty in seconds</target>
</trans-unit>
<trans-unit id="6bqsSb4" resname="my_event_details.courses_table.over_time_penalty_sec">
<source>my_event_details.courses_table.over_time_penalty_sec</source>
<target>Penalty per minute exceeded in second</target>
<target>Penalty per minute exceeded in seconds</target>
</trans-unit>
<trans-unit id="DDVg_8F" resname="my_events.modify_course.confirm">
<source>my_events.modify_course.confirm</source>
......@@ -1123,11 +1127,11 @@ such as orienteering, multisport orienteering, trails...</target>
</trans-unit>
<trans-unit id="g5gXHwR" resname="timeSheet.duration">
<source>timeSheet.duration</source>
<target>Duration</target>
<target>Leg time</target>
</trans-unit>