114 lines
3.9 KiB
TypeScript
114 lines
3.9 KiB
TypeScript
import { Body, Controller, Get, Param, Patch, Post, Query, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common';
|
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|
import { TripsService, RequestTripDto } from './trips.service';
|
|
import { TripAudioService } from './trip-audio.service';
|
|
import { TripStatus } from './entities/trip.entity';
|
|
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
|
import { RolesGuard } from '../auth/guards/roles.guard';
|
|
import { Roles } from '../auth/decorators/roles.decorator';
|
|
import { CurrentUser, AuthUser } from '../auth/decorators/current-user.decorator';
|
|
|
|
@ApiTags('trips')
|
|
@ApiBearerAuth()
|
|
@UseGuards(JwtAuthGuard)
|
|
@Controller('trips')
|
|
export class TripsController {
|
|
constructor(
|
|
private readonly trips: TripsService,
|
|
private readonly audio: TripAudioService,
|
|
) {}
|
|
|
|
/** سرد رحلات المستأجر — للوحة الأدمن، بترشيح الحالة (docs/22 — N4). */
|
|
@UseGuards(RolesGuard)
|
|
@Roles('admin', 'dispatcher')
|
|
@Get('admin/list')
|
|
adminList(
|
|
@CurrentUser() user: AuthUser,
|
|
@Query('status') status?: string,
|
|
@Query('rider') rider?: string,
|
|
) {
|
|
return this.trips.listByTenant(user.tenantId, status, rider);
|
|
}
|
|
|
|
// الراكب يطلب رحلة
|
|
@Post()
|
|
request(@CurrentUser() user: AuthUser, @Body() body: RequestTripDto) {
|
|
return this.trips.request(user.tenantId, user.userId, body);
|
|
}
|
|
|
|
@Get('mine')
|
|
mine(@CurrentUser() user: AuthUser) {
|
|
return this.trips.listForRider(user.tenantId, user.userId);
|
|
}
|
|
|
|
// السائق يسحب الطلبات المتاحة قربه (بديل/مكمّل للعرض المباشر)
|
|
@Get('available')
|
|
available(@CurrentUser() user: AuthUser) {
|
|
return this.trips.availableForDriver(user.tenantId, user.userId);
|
|
}
|
|
|
|
@Get(':id')
|
|
get(@CurrentUser() user: AuthUser, @Param('id') id: string) {
|
|
return this.trips.get(user.tenantId, id);
|
|
}
|
|
|
|
// السائق يقبل الرحلة
|
|
@Post(':id/accept')
|
|
accept(@CurrentUser() user: AuthUser, @Param('id') id: string) {
|
|
return this.trips.accept(user.tenantId, id, user.userId);
|
|
}
|
|
|
|
// تحديث الحالة (driver_arriving / driver_arrived / in_progress / completed / paid)
|
|
@Patch(':id/status')
|
|
status(
|
|
@CurrentUser() user: AuthUser,
|
|
@Param('id') id: string,
|
|
@Body('status') status: TripStatus,
|
|
) {
|
|
const actor = user.role === 'driver' ? 'driver' : 'rider';
|
|
return this.trips.updateStatus(user.tenantId, id, status, actor);
|
|
}
|
|
|
|
@Post(':id/cancel')
|
|
cancel(@CurrentUser() user: AuthUser, @Param('id') id: string) {
|
|
const actor = user.role === 'driver' ? 'driver' : 'rider';
|
|
return this.trips.cancel(user.tenantId, id, actor, user.userId);
|
|
}
|
|
|
|
// ---- التسجيل الصوتي (R2) ----
|
|
|
|
/** رفع مقطع صوتي مرتبط بالرحلة. */
|
|
@Post(':id/audio')
|
|
@UseInterceptors(FileInterceptor('file', { limits: { fileSize: 50 * 1024 * 1024 } }))
|
|
uploadAudio(
|
|
@CurrentUser() user: AuthUser,
|
|
@Param('id') id: string,
|
|
@UploadedFile() file: any,
|
|
@Body('duration_sec') durationSec?: string,
|
|
@Body('destination_name') destName?: string,
|
|
) {
|
|
const role = user.role === 'driver' ? 'driver' as const : 'rider' as const;
|
|
return this.audio.upload(user.tenantId, id, user.userId, role, file, {
|
|
duration_sec: durationSec ? parseInt(durationSec, 10) : undefined,
|
|
destination_name: destName,
|
|
});
|
|
}
|
|
|
|
/** كل المقاطع الصوتية للرحلة. */
|
|
@Get(':id/audio')
|
|
listAudio(@CurrentUser() user: AuthUser, @Param('id') id: string) {
|
|
return this.audio.listByTrip(user.tenantId, id);
|
|
}
|
|
|
|
/** رابط تحميل مقطع صوتي. */
|
|
@Get(':id/audio/:audioId')
|
|
getAudioUrl(
|
|
@CurrentUser() user: AuthUser,
|
|
@Param('id') id: string,
|
|
@Param('audioId') audioId: string,
|
|
) {
|
|
return this.audio.getDownloadUrl(user.tenantId, audioId);
|
|
}
|
|
}
|