diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 1e7cb6ed..88cee479 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -44,11 +44,17 @@ public function report(Exception $exception) { */ public function render($request, Exception $exception) { $request->headers->set('Accept', 'application/json'); + if ($exception instanceof HttpExceptionWithErrorCode) { + return response([ + 'code'=>$exception->getStatusCode(), + 'error_code'=>$exception->getErrorCode() + ], $exception->getStatusCode()); + } if ($exception instanceof HttpException) { return response([ 'code'=>$exception->getStatusCode(), - 'message'=>$exception->getMessage(), - ], $exception->getStatusCode(), $exception->getHeaders()); + 'message'=>$exception->getMessage() + ], $exception->getStatusCode()); } if ($exception instanceof ValidationException) { return response(['code'=>400, 'message'=> $exception->getMessage()], 400); diff --git a/app/Exceptions/HttpExceptionWithErrorCode.php b/app/Exceptions/HttpExceptionWithErrorCode.php new file mode 100644 index 00000000..f757dae8 --- /dev/null +++ b/app/Exceptions/HttpExceptionWithErrorCode.php @@ -0,0 +1,20 @@ +errorCode = $errorCode; + + parent::__construct($httpCode); + } + + public function getErrorCode() { + return $this->errorCode; + } +} diff --git a/app/Http/Controllers/ActivityLogController.php b/app/Http/Controllers/ActivityLogController.php new file mode 100644 index 00000000..036af468 --- /dev/null +++ b/app/Http/Controllers/ActivityLogController.php @@ -0,0 +1,42 @@ +validate($request, [ + 'id' => ['string'], + 'timestamp' => ['string'], + 'guest_id' => ['string'], + 'exh_id' => ['string'], + 'log_type' => ['string'], + 'reservation_id' => ['string'], + ]); + $log = ActivityLog::query(); + + foreach ($query as $i => $value) { + if ($i == 'reservation_id') { + if (!$request->user()->hasPermission('reservation')) { + abort(403); + } + if ($reservation = Reservation::find($value)) { + $log->where('guest_id', $reservation->guest->id); + } else return response([]); + } + $log->where($i, $value); + } + + return response()->json(ActivityLogResource::collection($log->get())); + } +} diff --git a/app/Http/Controllers/ExhibitionRoomController.php b/app/Http/Controllers/ExhibitionRoomController.php new file mode 100644 index 00000000..0ba76505 --- /dev/null +++ b/app/Http/Controllers/ExhibitionRoomController.php @@ -0,0 +1,120 @@ +capacity; + $exh_status[$exh->id] = new ExhibitionRoomResource($exh); + } + + $all_counts = []; + foreach (Term::all() as $term) { + $cnt = Guest::query()->whereNull('exited_at')->where('term_id', $term->id)->count(); + if ($cnt !== 0) $all_counts[$term->id] = $cnt; + } + return response()->json([ + 'exh' => $exh_status, + 'all' => [ + 'count' => $all_counts, + 'limit' => $all_limit + ] + ]); + } + + public function show(Request $request, $id) { + $exhibition = ExhibitionRoom::find($id); + if (!$exhibition) { + abort(404); + } + + return response()->json(new ExhibitionRoomResource($exhibition)); + } + + public function enter(Request $request) { + $this->validate($request, [ + 'guest_id' => ['string', 'required'] + ]); + + $user_id = $request->user()->id; + $guest = Guest::find($request->guest_id); + $exh = ExhibitionRoom::find($user_id); + $current = Carbon::now(); + + if (!$exh) throw new HttpExceptionWithErrorCode(400, 'EXHIBITION_NOT_FOUND'); + if (!$guest) throw new HttpExceptionWithErrorCode(400, 'GUEST_NOT_FOUND'); + + if ($guest->exh_id === $user_id) + throw new HttpExceptionWithErrorCode(400, 'GUEST_ALREADY_ENTERED'); + + if ($exh->capacity === $exh->guest_count) + throw new HttpExceptionWithErrorCode(400, 'PEOPLE_LIMIT_EXCEEDED'); + + if ($guest->exited_at !== null) + throw new HttpExceptionWithErrorCode(400, 'GUEST_ALREADY_EXITED'); + + if (new Carbon($guest->term->exit_scheduled_time) < $current) + throw new HttpExceptionWithErrorCode(400, 'EXIT_TIME_EXCEEDED'); + + + $guest->update(['exh_id' => $exh->id]); + + ActivityLog::create([ + 'exh_id' => $exh->id, + 'log_type' => 'enter', + 'guest_id' => $guest->id + ]); + + return response()->json(new GuestResource($guest)); + } + + public function exit(Request $request) { + $this->validate($request, [ + 'guest_id' => ['string', 'required'] + ]); + + $user_id = $request->user()->id; + $guest = Guest::find($request->guest_id); + $exh = ExhibitionRoom::find($user_id); + + if (!$exh) throw new HttpExceptionWithErrorCode(400, 'EXHIBITION_NOT_FOUND'); + if (!$guest) throw new HttpExceptionWithErrorCode(400, 'GUEST_NOT_FOUND'); + + if ($guest->exited_at !== null) + throw new HttpExceptionWithErrorCode(400, 'GUEST_ALREADY_EXITED'); + + $guest->update(['exh_id' => null]); + + ActivityLog::create([ + 'exh_id' => $exh->id, + 'log_type' => 'exit', + 'guest_id' => $guest->id + ]); + + return response()->json(new GuestResource($guest)); + } + + public function showLog(Request $request) { + $id = $request->user()->id; + $guest = ExhibitionRoom::find($id); + if (!$guest) { + abort(500, 'ExhibitionRoom Not found'); + } + $logs = ActivityLog::query()->where('exh_id', $id)->get(); + return response()->json(ActivityLogResource::collection($logs)); + } +} diff --git a/app/Http/Controllers/GuestController.php b/app/Http/Controllers/GuestController.php new file mode 100644 index 00000000..aaeb59f9 --- /dev/null +++ b/app/Http/Controllers/GuestController.php @@ -0,0 +1,101 @@ +json(new GuestResource($guest)); + } + + public function index() { + return response()->json(GuestResource::collection(Guest::all())); + } + + public function enter(Request $request) { + $this->validate($request, [ + 'reservation_id' => ['string', 'required'], + 'guest_id' => ['string', 'required'] + ]); + + if (!preg_match('/^[A-Z]{2,3}-[2-578ac-kmnpr-z]{5}$/', $request->guest_id)) { + throw new HttpExceptionWithErrorCode(400, 'INVALID_WRISTBAND_CODE'); + } + + $reservation = Reservation::find($request->reservation_id); + + if (!$reservation) throw new HttpExceptionWithErrorCode(400, 'RESERVATION_NOT_FOUND'); + + $reservation_error_code = $reservation->getErrorCode(); + + if ($reservation_error_code !== null) { + throw new HttpExceptionWithErrorCode(400, $reservation_error_code); + } + + if (Guest::find($request->guest_id)) { + throw new HttpExceptionWithErrorCode(400, 'ALREADY_USED_WRISTBAND'); + } + + $term = $reservation->term; + + if (strpos($request->guest_id, config('onsite.guest_types')[$term->guest_type]['prefix']) !== 0 + ) { + throw new HttpExceptionWithErrorCode(400, 'WRONG_WRISTBAND_COLOR'); + } + + + $guest = Guest::create( + [ + 'id' => $request->guest_id, + 'term_id' => $term->id, + 'reservation_id' => $request->reservation_id + ] + ); + + // TODO: 複数人で処理するときの扱いを考える (docsの編集待ち) + $reservation->update(['guest_id' => $guest->id]); + + return response()->json(new GuestResource($guest)); + } + + public function exit(Request $request) { + $this->validate($request, [ + 'guest_id' => ['string', 'required'] + ]); + + $guest = Guest::find($request->guest_id); + if (!$guest) { + throw new HttpExceptionWithErrorCode(400, 'GUEST_NOT_FOUND'); + } + + if ($guest->exited_at !== null) { + throw new HttpExceptionWithErrorCode(400, 'GUEST_ALREADY_EXITED'); + } + + $guest->update(['exited_at' => Carbon::now()]); + + return response()->json(new GuestResource($guest)); + } + + public function showLog(Request $request, $id) { + $guest = Guest::find($id); + if (!$guest) { + abort(404); + } + $logs = ActivityLog::query()->where('guest_id', $id)->get(); + return response()->json(ActivityLogResource::collection($logs)); + } +} diff --git a/app/Http/Controllers/ReservationController.php b/app/Http/Controllers/ReservationController.php new file mode 100644 index 00000000..8d54df46 --- /dev/null +++ b/app/Http/Controllers/ReservationController.php @@ -0,0 +1,81 @@ +validate($request, [ + 'email' => ['string', 'email:rfc,dns'], + 'term_id' => ['string'], + 'people_count' => ['integer', 'gte:1'], + 'name' => ['string'], + 'address' => ['string'], + 'cellphone' => ['string', 'regex:/0\d{9,10}$/'] + ]); + + $response = Reservation::query(); + + foreach ($query as $i => $value) $response->where($i, $value); + + + return response(ReservationResource::collection($response->get())); + } + public function create(Request $request) { + $body = $this->validate($request, [ + 'email' => ['required', 'string', 'email:rfc,dns'], + 'term_id' => ['required', 'string'], + 'people_count' => ['required', 'integer', 'gte:1'], + 'name' => ['required', 'string'], + 'address' => ['required', 'string'], + 'cellphone' => ['required', 'string', 'regex:/0\d{9,10}$/'] + ]); + + $salt = "234578acdefghijkmnprstuvwxyz"; + do { + $reservation_id = 'R-'; + while (strlen($reservation_id) < 10) { + $reservation_id .= $salt[mt_rand(0, strlen($salt) - 1)]; + } + } while (Reservation::where('id', $reservation_id)->exists()); + + $reservation = Reservation::create( + array_merge($body, ['id' => $reservation_id]) + ); + + return response($reservation, 201); + } + + public function show($id) { + $reservation = Reservation::find($id); + if (!$reservation) abort(404); + + return response()->json(new ReservationWithPrivateResource($reservation)); + } + + public function check($id) { + $reservation = Reservation::find($id); + if (!$reservation) abort(404); + + $status_code = $reservation->getErrorCode(); + if ($status_code !== null) { + $valid = false; + } else { + $valid = true; + } + + $res = [ + 'valid' => $valid, + 'status_code' => $status_code, + 'term' => $reservation->term + ]; + + return response()->json($res); + } +} diff --git a/app/Http/Controllers/TermController.php b/app/Http/Controllers/TermController.php new file mode 100644 index 00000000..f49af90d --- /dev/null +++ b/app/Http/Controllers/TermController.php @@ -0,0 +1,22 @@ +id] = [ + "enter_scheduled_time" => $term->enter_scheduled_time, + "exit_scheduled_time" => $term->exit_scheduled_time, + "guest_type" => $term->guest_type + ]; + } + + return response()->json($result); + } +} diff --git a/app/Http/Resources/ActivityLogResource.php b/app/Http/Resources/ActivityLogResource.php new file mode 100644 index 00000000..beeea697 --- /dev/null +++ b/app/Http/Resources/ActivityLogResource.php @@ -0,0 +1,24 @@ + $this->id, + 'timestamp' => $this->timestamp->toIso8601ZuluString(), + 'guest' => new GuestResource($this->guest), + 'exh_id' => $this->exh_id, + 'log_type' => $this->log_type + ]; + } +} diff --git a/app/Http/Resources/ExhibitionRoomResource.php b/app/Http/Resources/ExhibitionRoomResource.php new file mode 100644 index 00000000..02f69df2 --- /dev/null +++ b/app/Http/Resources/ExhibitionRoomResource.php @@ -0,0 +1,26 @@ + [ + 'name' => $this->name, + 'room_id' => $this->room_id, + 'thumbnail_image_id' => $this->thumbnail_image_id, + ], + 'count' => $this->countGuest(), + 'limit' => $this->capacity, + ]; + } +} diff --git a/app/Http/Resources/GuestResource.php b/app/Http/Resources/GuestResource.php new file mode 100644 index 00000000..c6b43f63 --- /dev/null +++ b/app/Http/Resources/GuestResource.php @@ -0,0 +1,24 @@ + $this->id, + 'term' => new TermResource($this->term), + 'entered_at' => $this->entered_at, + 'exited_at' => $this->exited_at, + 'exh_id' =>$this->exh_id, + ]; + } +} diff --git a/app/Http/Resources/ReservationResource.php b/app/Http/Resources/ReservationResource.php new file mode 100644 index 00000000..cbed0b70 --- /dev/null +++ b/app/Http/Resources/ReservationResource.php @@ -0,0 +1,23 @@ + $this->id, + 'email' => $this->email, + 'term' => $this->term, + 'people_count' => $this->people_count + ]; + } +} diff --git a/app/Http/Resources/ReservationWithPrivateResource.php b/app/Http/Resources/ReservationWithPrivateResource.php new file mode 100644 index 00000000..fb4de563 --- /dev/null +++ b/app/Http/Resources/ReservationWithPrivateResource.php @@ -0,0 +1,26 @@ + $this->id, + 'email' => $this->email, + 'term' => $this->term, + 'people_count' => $this->people_count, + 'name' => $this->name, + 'address' => $this->address, + 'cellphone' => $this->cellphone + ]; + } +} diff --git a/app/Http/Resources/TermResource.php b/app/Http/Resources/TermResource.php new file mode 100644 index 00000000..6386fb29 --- /dev/null +++ b/app/Http/Resources/TermResource.php @@ -0,0 +1,22 @@ + $this->enter_scheduled_time->toIso8601ZuluString(), + "exit_scheduled_time" => $this->exit_scheduled_time->toIso8601ZuluString(), + "guest_type" => $this->guest_type + ]; + } +} diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php new file mode 100644 index 00000000..d68d03f9 --- /dev/null +++ b/app/Models/ActivityLog.php @@ -0,0 +1,40 @@ +belongsTo('\App\Models\Guest'); + } +} diff --git a/app/Models/ExhibitionRoom.php b/app/Models/ExhibitionRoom.php new file mode 100644 index 00000000..68bbfb77 --- /dev/null +++ b/app/Models/ExhibitionRoom.php @@ -0,0 +1,53 @@ +hasMany('\App\Models\Guest', 'exh_id'); + } + + public function countGuest() { + $terms = Term::all(); + $res = []; + foreach ($terms as $term) { + $guest = $this->guests->where('term_id', $term->id); + $count = count($guest); + if ($count==0) continue; + $res[$term->id] = $count; + } + return $res; + } +} diff --git a/app/Models/Guest.php b/app/Models/Guest.php new file mode 100644 index 00000000..5b6b00b8 --- /dev/null +++ b/app/Models/Guest.php @@ -0,0 +1,48 @@ +belongsTo('\App\Models\Reservation'); + } + + public function logs() { + return $this->hasMany('\App\Models\ActivityLog'); + } + + public function term() { + return $this->belongsTo('\App\Models\Term'); + } +} diff --git a/app/Models/Reservation.php b/app/Models/Reservation.php new file mode 100644 index 00000000..4c80af18 --- /dev/null +++ b/app/Models/Reservation.php @@ -0,0 +1,58 @@ +belongsTo('\App\Models\Guest'); + } + + public function term() { + return $this->belongsTo('\App\Models\Term'); + } + + public function getErrorCode() { + $term = $this->term; + $current = Carbon::now(); + + if (new Carbon($term->enter_scheduled_time) >= $current + || new Carbon($term->exit_scheduled_time) < $current + ) { + return 'OUT_OF_RESERVATION_TIME'; + } + + if ($this->guest_id !== null) { + return 'ALREADY_ENTERED_RESERVATION'; + } + + return null; + } +} diff --git a/app/Models/Term.php b/app/Models/Term.php new file mode 100644 index 00000000..0d2cf93f --- /dev/null +++ b/app/Models/Term.php @@ -0,0 +1,37 @@ +configure('blog'); +$app->configure('onsite'); return $app; diff --git a/config/onsite.php b/config/onsite.php new file mode 100644 index 00000000..8a5d3704 --- /dev/null +++ b/config/onsite.php @@ -0,0 +1,48 @@ + [ + 'GuestBlue' => [ + 'prefix' => 'GB' + ], + 'GuestRed' => [ + 'prefix' => 'GR' + ], + 'GuestYellow' => [ + 'prefix' => 'GY' + ], + 'GuestPurple' => [ + 'prefix' => 'GP' + ], + 'GuestOrange' => [ + 'prefix' => 'GO' + ], + 'GuestGreen' => [ + 'prefix' => 'GG' + ], + 'GuestWhite' => [ + 'prefix' => 'GW' + ], + 'StudentGray' => [ + 'prefix' => 'SG' + ], + 'TestBlue' => [ + 'prefix' => 'TB' + ], + 'TestRed' => [ + 'prefix' => 'TR' + ], + 'TestYellow' => [ + 'prefix' => 'TY' + ] + ] +]; diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 94a593b2..bedf0922 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -107,3 +107,56 @@ 'mime_type' => 'image/png', ]; }); + +$factory->define(App\Models\Term::class, function (Faker\Generator $faker) { + return [ + 'id'=>$faker->userName, + 'enter_scheduled_time'=>$faker->dateTimeBetween('-1year', '-1hour'), + 'exit_scheduled_time'=>$faker->dateTimeBetween('+1hour', '+1year'), + 'guest_type'=>array_rand(config('onsite.guest_types')) + ]; +}); + +$factory->define(App\Models\ExhibitionRoom::class, function (Faker\Generator $faker) { + $capacity = $faker->numberBetween(1); + return [ + 'id'=>$faker->userName, + 'room_id'=>$faker->userName, + 'capacity'=>$capacity, + 'guest_count'=>$faker->numberBetween(0,$capacity-1), + 'updated_at'=>$faker->dateTime, + ]; +}); + +$factory->define(App\Models\Guest::class, function (Faker\Generator $faker) { + return [ + 'id'=>$faker->userName, + 'entered_at'=>$faker->dateTime, + 'exited_at'=>null, + 'exh_id'=>null, + 'term_id'=>$faker->userName, + 'reservation_id'=>$faker->userName, + ]; +}); + +$factory->define(App\Models\Reservation::class, function (Faker\Generator $faker) { + return [ + 'id'=>$faker->userName, + 'people_count'=>$faker->numberBetween(1), + 'name'=>$faker->name, + 'term_id'=>$faker->userName, + 'email'=>$faker->email, + 'address'=>$faker->address, + 'cellphone'=>$faker->phoneNumber, + 'guest_id'=>null + ]; +}); + +$factory->define(App\Models\ActivityLog::class, function (Faker\Generator $faker) { + return [ + 'timestamp'=>$faker->dateTime, + 'exh_id'=>$faker->userName, + 'log_type'=>$faker->randomElement(['exit','enter']), + 'guest_id'=>$faker->userName, + ]; +}); diff --git a/database/migrations/2020_08_25_021722_create_reservations_table.php b/database/migrations/2020_08_25_021722_create_reservations_table.php new file mode 100644 index 00000000..0ddaeb0c --- /dev/null +++ b/database/migrations/2020_08_25_021722_create_reservations_table.php @@ -0,0 +1,36 @@ +string('id'); + $table->primary('id'); + $table->string('email'); + $table->integer('people_count'); + $table->string('term_id'); + $table->string('name'); + $table->string('address'); + $table->string('cellphone'); + $table->string('guest_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::dropIfExists('reservations'); + } +} diff --git a/database/migrations/2020_08_25_023544_create_guests_table.php b/database/migrations/2020_08_25_023544_create_guests_table.php new file mode 100644 index 00000000..851ff06a --- /dev/null +++ b/database/migrations/2020_08_25_023544_create_guests_table.php @@ -0,0 +1,34 @@ +string('id'); + $table->primary('id'); + $table->timestamp('entered_at')->useCurrent(); + $table->timestamp('exited_at')->nullable(); + $table->string('reservation_id'); + $table->string('exh_id')->nullable(); + $table->string('term_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::dropIfExists('guests'); + } +} diff --git a/database/migrations/2020_08_25_024543_create_activity_logs_table.php b/database/migrations/2020_08_25_024543_create_activity_logs_table.php new file mode 100644 index 00000000..5b63e8c6 --- /dev/null +++ b/database/migrations/2020_08_25_024543_create_activity_logs_table.php @@ -0,0 +1,32 @@ +bigIncrements('id'); + $table->timestamp('timestamp')->useCurrent(); + $table->string('exh_id'); + $table->string('guest_id'); + $table->string('log_type'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::dropIfExists('activity_logs'); + } +} diff --git a/database/migrations/2020_08_25_111818_create_terms_table.php b/database/migrations/2020_08_25_111818_create_terms_table.php new file mode 100644 index 00000000..b7aa4c76 --- /dev/null +++ b/database/migrations/2020_08_25_111818_create_terms_table.php @@ -0,0 +1,32 @@ +string('id'); + $table->primary('id'); + $table->timestamp('enter_scheduled_time')->useCurrent(); + $table->timestamp('exit_scheduled_time')->useCurrent(); + $table->string('color_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::dropIfExists('terms'); + } +} diff --git a/database/migrations/2021_02_18_005707_create_exhibition_rooms_table.php b/database/migrations/2021_02_18_005707_create_exhibition_rooms_table.php new file mode 100644 index 00000000..9c456ad8 --- /dev/null +++ b/database/migrations/2021_02_18_005707_create_exhibition_rooms_table.php @@ -0,0 +1,33 @@ +string('id'); + $table->primary('id'); + $table->string('room_id'); + $table->unsignedInteger('capacity'); + $table->unsignedInteger('guest_count'); + $table->timestamp('updated_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::dropIfExists('exh_rooms'); + } +} diff --git a/database/migrations/2021_03_08_081853_rename_color_id_to_guest_type_on_terms_table.php b/database/migrations/2021_03_08_081853_rename_color_id_to_guest_type_on_terms_table.php new file mode 100644 index 00000000..8b1d41c8 --- /dev/null +++ b/database/migrations/2021_03_08_081853_rename_color_id_to_guest_type_on_terms_table.php @@ -0,0 +1,30 @@ +renameColumn('color_id', 'guest_type'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::table('terms', function (Blueprint $table) { + $table->renameColumn('guest_type', 'color_id'); + }); + } +} diff --git a/database/migrations/2021_03_20_144447_add_name_and_thumbnail_id_column.php b/database/migrations/2021_03_20_144447_add_name_and_thumbnail_id_column.php new file mode 100644 index 00000000..6a6987b3 --- /dev/null +++ b/database/migrations/2021_03_20_144447_add_name_and_thumbnail_id_column.php @@ -0,0 +1,32 @@ +string('name')->nullable(); + $table->string('thumbnail_image_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() { + Schema::table('exh_rooms', function (Blueprint $table) { + $table->dropColumn('name'); + $table->dropColumn('thumbnail_image_id'); + }); + } +} diff --git a/routes/web.php b/routes/web.php index a30f5fa8..1765a624 100644 --- a/routes/web.php +++ b/routes/web.php @@ -42,6 +42,35 @@ $router->get('/ogimage/articles/{id}', ['uses' => 'OGImageController@getArticleImage']); $router->get('/ogimage/preview', ['uses' => 'OGImageController@getPreview']); +$router->group(['prefix' => 'onsite'], function () use ($router) { + $router->group(['prefix' => 'reservation'], function () use ($router) { + $router->post('/', ['uses' => 'ReservationController@create']); + $router->get('search', ['uses' => 'ReservationController@index', 'middleware' => 'auth:reservation']); + $router->get('{id}', ['uses' => 'ReservationController@show', 'middleware' => 'auth:reservation']); + $router->get('{id}/check', ['uses' => 'ReservationController@check', 'middleware' => 'auth:reservation,general']); + }); + + $router->group(['prefix' => 'general'], function () use ($router) { + $router->group(['middleware' => 'auth:general'], function () use ($router) { + $router->get('guest', ['uses' => 'GuestController@index']); + $router->get('guest/{id}', ['uses' => 'GuestController@show']); + $router->get('guest/{id}/log', ['uses' => 'GuestController@showLog']); + $router->post('enter', ['uses' => 'GuestController@enter']); + $router->post('exit', ['uses' => 'GuestController@exit']); + }); + $router->get('term', ['uses' => 'TermController@index', 'middleware' => 'auth:general,exhibition']); + $router->get('log', ['uses' => 'ActivityLogController@index', 'middleware' => 'auth:general,exhibition,reservation']); + }); + + $router->group(['prefix' => 'exhibition'], function () use ($router) { + $router->get('status/{id}', ['uses' => 'ExhibitionRoomController@show', 'middleware' => 'auth:exhibition']); + $router->get('status', ['uses' => 'ExhibitionRoomController@index', 'middleware' => 'auth:exhibition,general']); + $router->get('log', ['uses' => 'ExhibitionRoomController@showLog', 'middleware' => 'auth:exhibition']); + $router->post('enter', ['uses' => 'ExhibitionRoomController@enter', 'middleware' => 'auth:exhibition']); + $router->post('exit', ['uses' => 'ExhibitionRoomController@exit', 'middleware' => 'auth:exhibition']); + }); +}); + $router->get('/online/exhibition', ['uses' => 'ExhibitionController@index']); $router->get('/online/exhibition/{id}', ['uses' => 'ExhibitionController@show']); $router->patch('/online/exhibition/{id}', ['uses' => 'ExhibitionController@patch', 'middleware'=>'auth:admin']); diff --git a/tests/onsite/General/EntranceTest.php b/tests/onsite/General/EntranceTest.php new file mode 100644 index 00000000..75911c71 --- /dev/null +++ b/tests/onsite/General/EntranceTest.php @@ -0,0 +1,300 @@ +create(); + $term = factory(Term::class)->create(); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest_id = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation->id] + ); + $this->assertResponseOk(); + } + + public function testInvalidGuestCode() { + $invalid_codes = []; + $count = 5; + + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + + for ($i = 0; $i < $count; ++$i) { + do { + $prefix = rand(1, 10); + $id = rand(1, 10); + } while ($prefix == 2 && $id == 5); + $invalid_codes[] = Str::random($prefix) . '-' . Str::random($id); + } + + foreach ($invalid_codes as $invalid_code) { + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $invalid_code, 'reservation_id' => $reservation->id] + ); + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('INVALID_WRISTBAND_CODE', $code); + } + } + + public function testAlreadyUsedGuestCode() { + $count = 5; + + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $used_id = []; + for ($i = 0; $i < $count; ++$i) { + $reservation_1 = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $reservation_2 = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + do { + $guest_id = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + } while (in_array($guest_id, $used_id)); + $used_id[] = $guest_id; + + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation_1->id] + ); + + $this->assertResponseOk(); + + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation_2->id] + ); + + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('ALREADY_USED_WRISTBAND', $code); + } + } + + public function testReservationNotFound() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $guest_id = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => 'R-' . Str::random(7)] + ); + + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('RESERVATION_NOT_FOUND', $code); + } + + // INVALID_RESERVATION_INFO: NO TEST + + public function testAlreadyEnteredReservation() { + $count = 5; + + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $used_id = []; + for ($i = 0; $i < $count; ++$i) { + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + + do { + $guest_id_1 = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + } while (in_array($guest_id_1, $used_id)); + $used_id[] = $guest_id_1; + + do { + $guest_id_2 = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + } while (in_array($guest_id_2, $used_id)); + $used_id[] = $guest_id_2; + + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id_1, 'reservation_id' => $reservation->id] + ); + + $this->assertResponseOk(); + + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id_1, 'reservation_id' => $reservation->id] + ); + + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('ALREADY_ENTERED_RESERVATION', $code); + } + } + + public function testOutOfReservationTime() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create([ + 'enter_scheduled_time' => DateTime::dateTimeBetween('-1 year', '-1 day'), + 'exit_scheduled_time' => DateTime::dateTimeBetween('-1 year', '-1 day') + ]); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest_id = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation->id] + ); + + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('OUT_OF_RESERVATION_TIME', $code); + + $term = factory(Term::class)->create([ + 'enter_scheduled_time' => DateTime::dateTimeBetween('+1 day', '+1 year'), + 'exit_scheduled_time' => DateTime::dateTimeBetween('+1 day', '+1 year') + ]); + + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation->id] + ); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest_id = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation->id] + ); + + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('OUT_OF_RESERVATION_TIME', $code); + } + + public function testWrongWristbandColor() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest_id = "XX" . "-" . Str::random(5); // 存在しないリストバンド prefix + $this->actingAs($user)->post( + '/onsite/general/enter', + ['guest_id' => $guest_id, 'reservation_id' => $reservation->id] + ); + + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('WRONG_WRISTBAND_COLOR', $code); + } + + public function testExit() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest = factory(Guest::class)->create([ + 'reservation_id' => $reservation->id + ]); + + $this->actingAs($user)->post( + '/onsite/general/exit', + ['guest_id' => $guest->id] + ); + $this->assertResponseOk(); + } + + public function testExitGuestNotFound() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $guest_id = config('onsite.guest_types')[$term->guest_type]['prefix'] . "-" . Str::random(5); + + + $this->actingAs($user)->post( + '/onsite/general/exit', + ['guest_id' => $guest_id] + ); + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('GUEST_NOT_FOUND', $code); + } + + public function testAlreadyExited() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest = factory(Guest::class)->create([ + 'reservation_id' => $reservation->id + ]); + + $this->actingAs($user)->post( + '/onsite/general/exit', + ['guest_id' => $guest->id] + ); + $this->actingAs($user)->post( + '/onsite/general/exit', + ['guest_id' => $guest->id] + ); + $this->assertResponseStatus(400); + $this->receiveJson(); + $code = json_decode($this->response->getContent())->error_code; + $this->assertEquals('GUEST_ALREADY_EXITED', $code); + } + + public function testForbidden() { + $users[] = factory(User::class, 'exhibition')->create(); + $users[] = factory(User::class, 'admin')->create(); // ADMIN perm doesnt mean all perm + $users[] = factory(User::class)->create(); + + $paths = [ + '/onsite/general/exit', '/onsite/general/enter', + ]; + + foreach ($users as $user) { + foreach ($paths as $path) { + $this->actingAs($user)->post($path); + $this->assertResponseStatus(403); + } + } + } + + public function testGuest() { + $paths = [ + '/onsite/general/exit', '/onsite/general/enter', + ]; + + foreach ($paths as $path) { + $this->post($path); + $this->assertResponseStatus(401); + } + } +} diff --git a/tests/onsite/General/GuestTest.php b/tests/onsite/General/GuestTest.php new file mode 100644 index 00000000..1d05f139 --- /dev/null +++ b/tests/onsite/General/GuestTest.php @@ -0,0 +1,71 @@ +create(); + + for ($i = 0; $i < $term_count; $i++) { + $term[] = factory(Term::class)->create(); + for ($j = 0; $j < $guest_count; $j++) { + $guest[] = factory(Guest::class)->create([ + 'term_id' => $term[$i]->id + ]); + } + } + + $this->actingAs($user)->get('/onsite/general/guest'); + $this->assertResponseOk(); + $this->receiveJson(); + $res = json_decode($this->response->getContent()); + $this->assertCount($term_count * $guest_count, $res); + } + + public function testShow() { + $user = factory(User::class, 'general')->create(); + $term = factory(Term::class)->create(); + + $guest = factory(Guest::class)->create([ + 'term_id' => $term->id, + ]); + + $this->actingAs($user)->get('/onsite/general/guest/' . $guest->id); + $this->assertResponseOk(); + $this->receiveJson(); + $res = json_decode($this->response->getContent()); + + $this->seeJsonEquals([ + 'id' => $guest->id, + 'entered_at' => $guest->entered_at, + 'exited_at' => $guest->exited_at, + 'exh_id' => $guest->exh_id, + 'term' => [ + 'enter_scheduled_time' => $term->enter_scheduled_time->toIso8601ZuluString(), + 'exit_scheduled_time' => $term->exit_scheduled_time->toIso8601ZuluString(), + 'guest_type' => $term->guest_type + ] + ]); + } + + public function testNotFound() { + $user = factory(User::class, 'general')->create(); + $id = Str::random(8); + $this->actingAs($user)->get("/onsite/general/guest/$id"); + + $this->assertResponseStatus(404); + } +} diff --git a/tests/onsite/General/LogTest.php b/tests/onsite/General/LogTest.php new file mode 100644 index 00000000..eab97008 --- /dev/null +++ b/tests/onsite/General/LogTest.php @@ -0,0 +1,62 @@ +create(); + $reservation = factory(Reservation::class)->create([ + 'term_id' => $term->id + ]); + $guest = factory(Guest::class)->create([ + 'reservation_id' => $reservation->id + ]); + $exh_user = factory(User::class, 'exhibition')->create(); + $exh = factory(Exhibition::class)->create([ + 'id' => $exh_user->id + ]); + $log = factory(ActivityLog::class)->create([ + 'exh_id' => $exh->id, + 'guest_id' => $guest->id, + ]); + + $this->actingAs($exh_user)->get('/onsite/general/log'); + $this->assertResponseOk(); + $this->receiveJson(); + $this->seeJsonEquals([ + [ + 'id' => $log->id, + 'timestamp' => $log->timestamp->toIso8601ZuluString(), + 'exh_id' => $exh->id, + 'guest' => new GuestResource($guest), + 'log_type' => $log->log_type, + ], + ]); + } + + public function testGetPermission() { + foreach (['general', 'exhibition', 'reservation'] as $perm) { + $user = factory(User::class, $perm)->create(); + + $this->actingAs($user)->get('/onsite/general/log'); + $this->assertResponseOk(); + } + + foreach (['blogAdmin', 'admin', 'blogWriter', 'teacher'] as $perm) { + $user = factory(User::class, $perm)->create(); + $this->actingAs($user)->get('/onsite/general/log'); + $this->assertResponseStatus(403); + } + } +}