Explorar el Código

sorting fix, inactive login not possible etc

master
Daniel hace 10 meses
padre
commit
16a6f51176
Se han modificado 11 ficheros con 102 adiciones y 37 borrados
  1. +1
    -0
      angular/src/app/_components/search-select/search-select.component.ts
  2. +8
    -0
      angular/src/app/_views/trip/trip-list/trip-list.component.ts
  3. +11
    -11
      angular/src/app/app-routing.module.ts
  4. +2
    -1
      angular/src/assets/i18n/en.json
  5. +2
    -1
      httpdocs/src/ApiResource/UserTripApi.php
  6. +14
    -2
      httpdocs/src/Entity/Trip.php
  7. +5
    -0
      httpdocs/src/Entity/User.php
  8. +0
    -5
      httpdocs/src/EventListener/AuthenticationSuccessListener.php
  9. +25
    -16
      httpdocs/src/Security/JwtAuthenticator.php
  10. +3
    -1
      httpdocs/src/State/EntityClassDtoStateProcessor.php
  11. +31
    -0
      httpdocs/src/State/UserTripStateProcessor.php

+ 1
- 0
angular/src/app/_components/search-select/search-select.component.ts Ver fichero

@@ -120,6 +120,7 @@ export class SearchSelectComponent implements OnInit, AfterViewInit {
text: 'model.zone', text: 'model.zone',
type: ListComponent.COLUMN_TYPE_TEXT, type: ListComponent.COLUMN_TYPE_TEXT,
subResource: 'zone', subResource: 'zone',
sortingSubResource: 'zone',
field: 'name', field: 'name',
sortable: true, sortable: true,
filterType: FilterBarComponent.FILTER_TYPE_TEXT, filterType: FilterBarComponent.FILTER_TYPE_TEXT,


+ 8
- 0
angular/src/app/_views/trip/trip-list/trip-list.component.ts Ver fichero

@@ -83,6 +83,14 @@ export class TripListComponent {
sortable: true, sortable: true,
filterType: FilterBarComponent.FILTER_TYPE_DATE, filterType: FilterBarComponent.FILTER_TYPE_DATE,
} as ListColDefinition, } as ListColDefinition,
{
name: 'completed',
text: 'trip.completed',
type: ListComponent.COLUMN_TYPE_BOOLEAN,
field: 'completed',
sortable: true,
filterType: FilterBarComponent.FILTER_TYPE_BOOLEAN,
} as ListColDefinition,
{ {
name: 'createdAt', name: 'createdAt',
text: 'common.created_at', text: 'common.created_at',


+ 11
- 11
angular/src/app/app-routing.module.ts Ver fichero

@@ -41,7 +41,7 @@ const routes: Routes = [
{ {
path: ROUTE_DASHBOARD, path: ROUTE_DASHBOARD,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: '', component: DashboardComponent}, {path: '', component: DashboardComponent},
] ]
@@ -49,7 +49,7 @@ const routes: Routes = [
{ {
path: ROUTE_BASE_DATA, path: ROUTE_BASE_DATA,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: '', component: BaseDataComponent}, {path: '', component: BaseDataComponent},
] ]
@@ -57,7 +57,7 @@ const routes: Routes = [
{ {
path: ROUTE_LOCATIONS, path: ROUTE_LOCATIONS,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: ':id', component: LocationDetailComponent}, {path: ':id', component: LocationDetailComponent},
] ]
@@ -65,7 +65,7 @@ const routes: Routes = [
{ {
path: ROUTE_TRIPS, path: ROUTE_TRIPS,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: '', component: TripComponent}, {path: '', component: TripComponent},
] ]
@@ -73,7 +73,7 @@ const routes: Routes = [
{ {
path: ROUTE_TRIPS, path: ROUTE_TRIPS,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: ':id', component: TripDetailComponent}, {path: ':id', component: TripDetailComponent},
] ]
@@ -81,7 +81,7 @@ const routes: Routes = [
{ {
path: ROUTE_USER_TRIPS, path: ROUTE_USER_TRIPS,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: '', component: UserTripComponent}, {path: '', component: UserTripComponent},
] ]
@@ -89,7 +89,7 @@ const routes: Routes = [
{ {
path: ROUTE_USER_TRIPS, path: ROUTE_USER_TRIPS,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: ':id', component: UserTripDetailComponent}, {path: ':id', component: UserTripDetailComponent},
] ]
@@ -97,7 +97,7 @@ const routes: Routes = [
{ {
path: ROUTE_ZONES, path: ROUTE_ZONES,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: ':id', component: ZoneDetailComponent}, {path: ':id', component: ZoneDetailComponent},
] ]
@@ -105,7 +105,7 @@ const routes: Routes = [
{ {
path: ROUTE_VESSELS, path: ROUTE_VESSELS,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: ':id', component: VesselDetailComponent}, {path: ':id', component: VesselDetailComponent},
] ]
@@ -113,7 +113,7 @@ const routes: Routes = [
{ {
path: ROUTE_SHIPPING_COMPANIES, path: ROUTE_SHIPPING_COMPANIES,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: ':id', component: ShippingCompanyDetailComponent}, {path: ':id', component: ShippingCompanyDetailComponent},
] ]
@@ -121,7 +121,7 @@ const routes: Routes = [
{ {
path: ROUTE_PROFILE, path: ROUTE_PROFILE,
component: TwoColumnComponent, component: TwoColumnComponent,
canActivate: [userGuard],
canActivate: [adminGuard],
children: [ children: [
{path: '', component: ProfileComponent}, {path: '', component: ProfileComponent},
] ]


+ 2
- 1
angular/src/assets/i18n/en.json Ver fichero

@@ -40,7 +40,8 @@
"save_itinerary": "Save itinerary", "save_itinerary": "Save itinerary",
"assigned_users": "Assigned Pilots", "assigned_users": "Assigned Pilots",
"save_user_assignments": "Save user assignments", "save_user_assignments": "Save user assignments",
"events": "Events"
"events": "Events",
"completed": "Completed"
}, },
"user_trip": "user_trip":
{ {


+ 2
- 1
httpdocs/src/ApiResource/UserTripApi.php Ver fichero

@@ -18,6 +18,7 @@ use App\Filter\CustomJsonFilter;
use App\Filter\CustomJsonOrderFilter; use App\Filter\CustomJsonOrderFilter;
use App\State\EntityClassDtoStateProcessor; use App\State\EntityClassDtoStateProcessor;
use App\State\EntityToDtoStateProvider; use App\State\EntityToDtoStateProvider;
use App\State\UserTripStateProcessor;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\PropertyInfo\Type; use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotBlank;
@@ -43,7 +44,7 @@ use Symfony\Component\Validator\Constraints\NotBlank;
], ],
security: 'is_granted("ROLE_USER")', security: 'is_granted("ROLE_USER")',
provider: EntityToDtoStateProvider::class, provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,
processor: UserTripStateProcessor::class,
stateOptions: new Options(entityClass: UserTrip::class), stateOptions: new Options(entityClass: UserTrip::class),
)] )]
#[ApiFilter(SearchFilter::class, properties: [ #[ApiFilter(SearchFilter::class, properties: [


+ 14
- 2
httpdocs/src/Entity/Trip.php Ver fichero

@@ -156,8 +156,20 @@ class Trip
return $this->completed; return $this->completed;
} }


public function setCompleted(bool $completed): void
{
public function setCompleted(): void
{
$completed = true;
if (count($this->userTrips) <= 0) {
$completed = false;
} else {
/** @var UserTrip $userTrip */
foreach ($this->userTrips as $userTrip) {
if (!$userTrip->isCompleted() || !$userTrip->isApproved()) {
$completed = false;
break;
}
}
}
$this->completed = $completed; $this->completed = $completed;
} }




+ 5
- 0
httpdocs/src/Entity/User.php Ver fichero

@@ -193,6 +193,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
$this->isPilot = $isPilot; $this->isPilot = $isPilot;
} }


public function isAdmin()
{
return in_array(User::ROLE_ADMIN, $this->roles, true);
}

public function getCreatedAt(): ?\DateTimeImmutable public function getCreatedAt(): ?\DateTimeImmutable
{ {
return $this->createdAt; return $this->createdAt;


+ 0
- 5
httpdocs/src/EventListener/AuthenticationSuccessListener.php Ver fichero

@@ -1,9 +1,4 @@
<?php <?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 18.01.24
*/



namespace App\EventListener; namespace App\EventListener;




+ 25
- 16
httpdocs/src/Security/JwtAuthenticator.php Ver fichero

@@ -1,15 +1,8 @@
<?php <?php
// src/Security/JwtAuthenticator.php
namespace App\Security; namespace App\Security;


use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\IriConverterInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\State\Provider\ContentNegotiationProvider;
use ApiPlatform\State\SerializerContextBuilderInterface;
use App\ApiResource\UserApi;
use App\Entity\MediaObject;
use App\Entity\User; use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -21,14 +14,12 @@ use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;


class JwtAuthenticator extends AbstractAuthenticator class JwtAuthenticator extends AbstractAuthenticator
{ {
public function __construct( public function __construct(
private JWTTokenManagerInterface $jwtManager
private JWTTokenManagerInterface $jwtManager,
private EntityManagerInterface $em
) {} ) {}


public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
@@ -51,20 +42,38 @@ class JwtAuthenticator extends AbstractAuthenticator
public function authenticate(Request $request): Passport public function authenticate(Request $request): Passport
{ {
$data = json_decode($request->getContent(), true); $data = json_decode($request->getContent(), true);

if (!$data) { if (!$data) {
throw new CustomUserMessageAuthenticationException('Invalid JSON.');
throw new CustomUserMessageAuthenticationException('Ungültige JSON-Daten.');
} }


$email = $data['email'] ?? '';
$email = $data['email'] ?? '';
$password = $data['password'] ?? ''; $password = $data['password'] ?? '';


$userBadge = new UserBadge($email, function(string $userIdentifier) {
$user = $this->em
->getRepository(User::class)
->findOneBy(['email' => $userIdentifier]);

if (!$user) {
// Standardnachricht für nicht gefundene E-Mail
throw new CustomUserMessageAuthenticationException('Invalid email or password.');
}

if (!$user->isActive()) {
// custom Message, erscheint im JSON-Response
throw new CustomUserMessageAuthenticationException('Your account is currently deactivated.');
}

return $user;
});

return new Passport( return new Passport(
new UserBadge($email),
$userBadge,
new PasswordCredentials($password) new PasswordCredentials($password)
); );
} }



public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{ {
return new JsonResponse([ return new JsonResponse([


+ 3
- 1
httpdocs/src/State/EntityClassDtoStateProcessor.php Ver fichero

@@ -8,6 +8,7 @@ use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\DeleteOperationInterface; use ApiPlatform\Metadata\DeleteOperationInterface;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfonycasts\MicroMapper\MicroMapperInterface; use Symfonycasts\MicroMapper\MicroMapperInterface;


@@ -16,7 +17,8 @@ class EntityClassDtoStateProcessor implements ProcessorInterface
public function __construct( public function __construct(
#[Autowire(service: PersistProcessor::class)] private ProcessorInterface $persistProcessor, #[Autowire(service: PersistProcessor::class)] private ProcessorInterface $persistProcessor,
#[Autowire(service: RemoveProcessor::class)] private ProcessorInterface $removeProcessor, #[Autowire(service: RemoveProcessor::class)] private ProcessorInterface $removeProcessor,
private MicroMapperInterface $microMapper
private MicroMapperInterface $microMapper,
protected EntityManagerInterface $em
) )
{} {}




+ 31
- 0
httpdocs/src/State/UserTripStateProcessor.php Ver fichero

@@ -0,0 +1,31 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 29.04.25
*/


namespace App\State;


use ApiPlatform\Metadata\Operation;
use App\Entity\Trip;

class UserTripStateProcessor extends EntityClassDtoStateProcessor
{


public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
{
$res = parent::process($data, $operation, $uriVariables, $context);

/** @var Trip $trip */
$trip = $this->em->getRepository(Trip::class)->find($data->tripIri->id);
$trip->setCompleted();
$this->em->flush();

return $res;
}


}

Cargando…
Cancelar
Guardar