From 48846ea523693372037f516d44b1512b34d34aed Mon Sep 17 00:00:00 2001
From: "Dest.Com" <37459465+DestroyCom@users.noreply.github.com>
Date: Thu, 14 Sep 2023 18:23:23 +0200
Subject: [PATCH 01/27] docs: fix lucalg322 github link
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index bca4911..e3d7df1 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,7 @@ sh dev.sh
- [@DestroyCom](https://github.com/DestroyCom)
- [@ADR1811](https://github.com/ADR1811)
-- [@lucag322](https://github.com/ADR1811)
+- [@lucag322](https://github.com/lucag322)
- [@ThomAzgo](https://github.com/ThomAzgo)
- [@Hiteazel](https://github.com/Hiteazel)
From f7fb508b80e625953eb1fe5b41f384e3598a102e Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Thu, 14 Sep 2023 23:19:42 +0200
Subject: [PATCH 02/27] =?UTF-8?q?feat(Project):=20Publish=20Unpublish=20?=
=?UTF-8?q?=F0=9F=A4=8C=F0=9F=A4=8C=F0=9F=A4=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Http/Controllers/ProjectController.php | 6 +-
.../app/Http/Controllers/StepController.php | 134 +++++++++++++++
sera-back/config/roles.php | 4 +-
.../database/factories/ProjectFactory.php | 2 +-
...023_07_04_134808_create_projects_table.php | 3 +-
sera-back/routes/api.php | 2 +
sera-back/storage/api-docs/api-docs.json | 162 +++++++++++++++++-
7 files changed, 304 insertions(+), 9 deletions(-)
diff --git a/sera-back/app/Http/Controllers/ProjectController.php b/sera-back/app/Http/Controllers/ProjectController.php
index f1a562e..ba601c6 100644
--- a/sera-back/app/Http/Controllers/ProjectController.php
+++ b/sera-back/app/Http/Controllers/ProjectController.php
@@ -69,7 +69,7 @@ public function index(Request $request)
$request->validate([
'maxPerPage' => 'integer',
'sort' => 'string|in:asc,desc',
- 'status' => 'string|in:ongoing,completed,cancelled',
+ 'status' => 'string|in:ongoing,published,cancelled',
]);
$maxPerPage = $request->input('maxPerPage', 10);
@@ -366,7 +366,7 @@ public function show($id)
* @OA\Property(
* property="status",
* type="string",
- * enum={"ongoing", "completed", "cancelled"},
+ * enum={"ongoing", "published", "cancelled"},
* ),
* @OA\Property(
* property="change_color",
@@ -435,7 +435,7 @@ public function update(Request $request, $id): JsonResponse
'description' => 'string',
'start_date' => 'date',
'end_date' => 'date',
- 'status' => 'string|in:ongoing,completed,cancelled',
+ 'status' => 'string|in:ongoing,published,cancelled',
'change_color' => 'boolean',
]);
diff --git a/sera-back/app/Http/Controllers/StepController.php b/sera-back/app/Http/Controllers/StepController.php
index cf4704f..93803f8 100644
--- a/sera-back/app/Http/Controllers/StepController.php
+++ b/sera-back/app/Http/Controllers/StepController.php
@@ -654,4 +654,138 @@ public function validateTranscription(Request $request, $project_id){
return response()->json($transcriptions, 200);
}
+
+ /**
+ * @OA\Post(
+ * path="/api/projects/{project_id}/publish",
+ * tags={"Projects"},
+ * summary="Publish project",
+ * description="Publish project",
+ * operationId="PublishProject",
+ * @OA\Parameter(
+ * description="Project id",
+ * in="path",
+ * name="project_id",
+ * required=true,
+ * @OA\Schema(
+ * type="integer",
+ * format="int64"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Project published",
+ * @OA\JsonContent(
+ * @OA\Property(property="id", type="integer", example="1"),
+ * @OA\Property(property="title", type="string", example="Project title"),
+ * @OA\Property(property="description", type="string", example="Project description"),
+ * @OA\Property(property="status", type="string", example="published"),
+ * @OA\Property(property="created_at", type="string", example="2021-05-05T14:48:00.000000Z"),
+ * @OA\Property(property="updated_at", type="string", example="2021-05-05T14:48:00.000000Z"),
+ * @OA\Property(property="project_request_id", type="integer", example="1"),
+ * ),
+ * ),
+ * @OA\Response(
+ * response=400,
+ * description="Bad request",
+ * @OA\JsonContent(
+ * @OA\Property(property="error", type="string", example="Project has no subtitles."),
+ * ),
+ * ),
+ * )
+ */
+ public function publish($project_id){
+ $project = Project::find($project_id);
+
+ if ($project === null) {
+ return response()->json(['error' => 'Project not found.'], 404);
+ }
+
+ $steps = json_decode($project->steps);
+
+ // il faut que toutes les steps soient done et que Subtitling soit ongoing
+ foreach ($steps as $step => $value) {
+ if($value->status !== 'done' && $step !== 'Subtitling' && $step !== 'Editorial'){
+ return response()->json(['error' => 'Step ' . $step . ' is not done.'], 400);
+ }
+ }
+
+ $subtitles = $project->subtitles()->get();
+
+ // is empty
+ if($subtitles->isEmpty()){
+ return response()->json(['error' => 'Project has no subtitles.'], 400);
+ }
+
+ $editorials = $project->edito()->get();
+
+ if($editorials->isEmpty()){
+ return response()->json(['error' => 'Project has no editorials.'], 400);
+ }
+ // on passe le status du projet à published
+ $project->status = 'published';
+
+ $project->save();
+
+ return response()->json('Project published' , 200);
+ }
+
+ /**
+ * @OA\Post(
+ * path="/api/projects/{project_id}/unpublish",
+ * tags={"Projects"},
+ * summary="Unpublish project",
+ * description="Unpublish project",
+ * operationId="UnpublishProject",
+ * @OA\Parameter(
+ * description="Project id",
+ * in="path",
+ * name="project_id",
+ * required=true,
+ * @OA\Schema(
+ * type="integer",
+ * format="int64"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="Project unpublished",
+ * @OA\JsonContent(
+ * @OA\Property(property="id", type="integer", example="1"),
+ * @OA\Property(property="title", type="string", example="Project title"),
+ * @OA\Property(property="description", type="string", example="Project description"),
+ * @OA\Property(property="status", type="string", example="ongoing"),
+ * @OA\Property(property="created_at", type="string", example="2021-05-05T14:48:00.000000Z"),
+ * @OA\Property(property="updated_at", type="string", example="2021-05-05T14:48:00.000000Z"),
+ * @OA\Property(property="project_request_id", type="integer", example="1"),
+ * ),
+ * ),
+ * @OA\Response(
+ * response=400,
+ * description="Bad request",
+ * @OA\JsonContent(
+ * @OA\Property(property="error", type="string", example="Project is not published."),
+ * ),
+ * ),
+ * )
+ */
+ public function unpublish($project_id){
+ $project = Project::find($project_id);
+
+ if ($project === null) {
+ return response()->json(['error' => 'Project not found.'], 404);
+ }
+
+ // il faut que le status du projet soit published
+ if($project->status !== 'published'){
+ return response()->json(['error' => 'Project is not published.'], 400);
+ }
+
+ $project->status = 'ongoing';
+
+ $project->save();
+
+ return response()->json('Project unpublished' , 200);
+ }
+
}
diff --git a/sera-back/config/roles.php b/sera-back/config/roles.php
index 57eec44..ef241dd 100644
--- a/sera-back/config/roles.php
+++ b/sera-back/config/roles.php
@@ -6,7 +6,7 @@
"cursus_director" => [
"projects-requests" => ["show", "index", "store", "update", "destroy"],
"users" => ["iso","show", "index", "store", "update", "destroy", "roles", "image", "password","reservations","reservations"],
- "projects" => ["validateTranscription","getCaptionUrl","show", "index", "store", "update", "destroy", "init","stepsGet","stepsUpdateDate","planificationToCaptation","addLink","captationToPostproduction","validatePostProd"],
+ "projects" => ["unpublish","publish","validateTranscription","getCaptionUrl","show", "index", "store", "update", "destroy", "init","stepsGet","stepsUpdateDate","planificationToCaptation","addLink","captationToPostproduction","validatePostProd"],
"teams" => ["add", "index", "show", "remove"],
"rooms" => ["show", "index", "store", "update", "destroy", "reserve","unreserve","available","showByProject"],
"video-reviews" => ["getReviewsByProjectId","store","destroy","addAComment","getTemporaryUploadUrl","getVideoValidated"],
@@ -20,7 +20,7 @@
"project_manager" => [
"projects-requests" => ["show", "index", "update"],
"users" => ["iso","show", "index", "store", "update", "destroy", "roles", "image", "password","reservations"],
- "projects" => ["validateTranscription","getCaptionUrl","show", "index", "store", "update", "destroy", "init","stepsGet","stepsUpdateDate","planificationToCaptation","addLink","captationToPostproduction","validatePostProd"],
+ "projects" => ["unpublish","publish","validateTranscription","getCaptionUrl","show", "index", "store", "update", "destroy", "init","stepsGet","stepsUpdateDate","planificationToCaptation","addLink","captationToPostproduction","validatePostProd"],
"teams" => ["add", "index", "show", "remove"],
"rooms" => ["show", "index", "reserve","unreserve","available","showByProject"],
"video-reviews" => ["getReviewsByProjectId","store","destroy","addAComment","getTemporaryUploadUrl","getVideoValidated"],
diff --git a/sera-back/database/factories/ProjectFactory.php b/sera-back/database/factories/ProjectFactory.php
index b7874e6..3e29f40 100644
--- a/sera-back/database/factories/ProjectFactory.php
+++ b/sera-back/database/factories/ProjectFactory.php
@@ -19,7 +19,7 @@ class ProjectFactory extends Factory
*/
public function definition(): array
{
- $statusArray = ["ongoing", "completed", "cancelled"];
+ $statusArray = ["ongoing", "published", "cancelled"];
$defaultSteps = config('steps');
$projectRequest = ProjectRequest::factory()->create();
diff --git a/sera-back/database/migrations/2023_07_04_134808_create_projects_table.php b/sera-back/database/migrations/2023_07_04_134808_create_projects_table.php
index 1f6ea35..5aabeac 100644
--- a/sera-back/database/migrations/2023_07_04_134808_create_projects_table.php
+++ b/sera-back/database/migrations/2023_07_04_134808_create_projects_table.php
@@ -17,12 +17,11 @@ public function up(): void
Schema::create('projects', function (Blueprint $table) {
$defaultSteps = config('steps');
-
$table->id();
$table->foreignId('project_request_id')->constrained('project_requests')->cascadeOnDelete()->cascadeOnUpdate();
$table->string('title');
$table->longText('description');
- $table->enum('status', ['ongoing', 'completed', 'cancelled'])->default('ongoing');
+ $table->enum('status', ['ongoing', 'published', 'cancelled'])->default('ongoing');
$table->string('start_date')->nullable();
$table->string('end_date')->nullable();
$table->json('colors')->nullable();
diff --git a/sera-back/routes/api.php b/sera-back/routes/api.php
index b1573ff..94dd3bf 100644
--- a/sera-back/routes/api.php
+++ b/sera-back/routes/api.php
@@ -57,6 +57,8 @@
Route::post('projects/{project_id}/captation-to-postproduction', 'App\Http\Controllers\StepController@captationToPostProd')->name('projects.captationToPostproduction');
Route::post('projects/{project_id}/validate/postproduction', 'App\Http\Controllers\StepController@validatePostProd')->name('projects.validatePostProd');
Route::post('projects/{project_id}/validate/transcription', 'App\Http\Controllers\StepController@validateTranscription')->name('projects.validateTranscription');
+ Route::post('projects/{project_id}/publish', 'App\Http\Controllers\StepController@publish')->name('projects.publish');
+ Route::post('projects/{project_id}/unpublish', 'App\Http\Controllers\StepController@unpublish')->name('projects.unpublish');
/****TEAM ****/
diff --git a/sera-back/storage/api-docs/api-docs.json b/sera-back/storage/api-docs/api-docs.json
index abc8898..63db2e9 100644
--- a/sera-back/storage/api-docs/api-docs.json
+++ b/sera-back/storage/api-docs/api-docs.json
@@ -1504,7 +1504,7 @@
"type": "string",
"enum": [
"ongoing",
- "completed",
+ "published",
"cancelled"
]
},
@@ -4080,6 +4080,166 @@
}
}
},
+ "/api/projects/{project_id}/publish": {
+ "post": {
+ "tags": [
+ "Projects"
+ ],
+ "summary": "Publish project",
+ "description": "Publish project",
+ "operationId": "PublishProject",
+ "parameters": [
+ {
+ "name": "project_id",
+ "in": "path",
+ "description": "Project id",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Project published",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "id": {
+ "type": "integer",
+ "example": "1"
+ },
+ "title": {
+ "type": "string",
+ "example": "Project title"
+ },
+ "description": {
+ "type": "string",
+ "example": "Project description"
+ },
+ "status": {
+ "type": "string",
+ "example": "published"
+ },
+ "created_at": {
+ "type": "string",
+ "example": "2021-05-05T14:48:00.000000Z"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2021-05-05T14:48:00.000000Z"
+ },
+ "project_request_id": {
+ "type": "integer",
+ "example": "1"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "error": {
+ "type": "string",
+ "example": "Project has no subtitles."
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/projects/{project_id}/unpublish": {
+ "post": {
+ "tags": [
+ "Projects"
+ ],
+ "summary": "Unpublish project",
+ "description": "Unpublish project",
+ "operationId": "UnpublishProject",
+ "parameters": [
+ {
+ "name": "project_id",
+ "in": "path",
+ "description": "Project id",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Project unpublished",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "id": {
+ "type": "integer",
+ "example": "1"
+ },
+ "title": {
+ "type": "string",
+ "example": "Project title"
+ },
+ "description": {
+ "type": "string",
+ "example": "Project description"
+ },
+ "status": {
+ "type": "string",
+ "example": "ongoing"
+ },
+ "created_at": {
+ "type": "string",
+ "example": "2021-05-05T14:48:00.000000Z"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2021-05-05T14:48:00.000000Z"
+ },
+ "project_request_id": {
+ "type": "integer",
+ "example": "1"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "error": {
+ "type": "string",
+ "example": "Project is not published."
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/projects/{projectId}/subtitles": {
"get": {
"tags": [
From 3739c6ed6452a8c6a0b785413d5b219bf8f76e8a Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 00:03:14 +0200
Subject: [PATCH 03/27] =?UTF-8?q?feat(ApiKey):=20Create/Recreate/Destroy/G?=
=?UTF-8?q?ets=20(=E2=9D=81=C2=B4=E2=97=A1`=E2=9D=81)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../app/Http/Controllers/ApiKeyController.php | 194 ++++++++++++++
sera-back/app/Models/ApiKey.php | 12 +
sera-back/config/roles.php | 3 +-
...023_09_14_213435_create_api_keys_table.php | 32 +++
sera-back/routes/api.php | 6 +
sera-back/storage/api-docs/api-docs.json | 240 ++++++++++++++++++
6 files changed, 486 insertions(+), 1 deletion(-)
create mode 100644 sera-back/app/Http/Controllers/ApiKeyController.php
create mode 100644 sera-back/app/Models/ApiKey.php
create mode 100644 sera-back/database/migrations/2023_09_14_213435_create_api_keys_table.php
diff --git a/sera-back/app/Http/Controllers/ApiKeyController.php b/sera-back/app/Http/Controllers/ApiKeyController.php
new file mode 100644
index 0000000..ed929df
--- /dev/null
+++ b/sera-back/app/Http/Controllers/ApiKeyController.php
@@ -0,0 +1,194 @@
+validate([
+ 'name' => 'required|string',
+ 'description' => 'nullable|string',
+ 'expires_at' => 'required|date',
+ 'never_expires' => 'required|boolean',
+ ]);
+
+ $apiKey = new ApiKey;
+ $apiKey->user_id = $request->user()->id;
+ $apiKey->key = bin2hex(random_bytes(32));
+ $apiKey->name = $validated['name'];
+ $apiKey->description = $validated['description'];
+ $apiKey->expires_at = $validated['never_expires'] ? null : $validated['expires_at'];
+ $apiKey->save();
+
+ return response()->json([
+ 'message' => 'API key created successfully',
+ 'data' => $apiKey,
+ ], 201);
+ }
+
+ /**
+ * @OA\Post(
+ * path="/api/api-keys/{apikey_id}/recreate",
+ * tags={"API Key"},
+ * summary="Recreate an API key",
+ * description="Recreate an API key",
+ * @OA\Parameter(
+ * name="apikey_id",
+ * in="path",
+ * description="ID of the API key to recreate",
+ * required=true,
+ * @OA\Schema(
+ * type="integer",
+ * format="int64"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="API key recreated successfully",
+ * @OA\JsonContent(
+ * @OA\Property(property="message", type="string", example="API key recreated successfully"),
+ * )
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="API key not found",
+ * @OA\JsonContent(
+ * @OA\Property(property="message", type="string", example="API key not found"),
+ * )
+ * ),
+ * )
+ */
+ public function recreate($apikey_id)
+ {
+ $apiKey = ApiKey::find($apikey_id);
+
+ if (!$apiKey) {
+ return response()->json([
+ 'message' => 'API key not found',
+ ], 404);
+ }
+
+ $apiKey->key = bin2hex(random_bytes(32));
+ $apiKey->save();
+
+ return response()->json([
+ 'message' => 'API key recreated successfully',
+ 'data' => $apiKey,
+ ], 200);
+ }
+
+ /**
+ * @OA\Delete(
+ * path="/api/api-keys/{apikey_id}",
+ * tags={"API Key"},
+ * summary="Delete an API key",
+ * description="Delete an API key",
+ * @OA\Parameter(
+ * name="apikey_id",
+ * in="path",
+ * description="ID of the API key to delete",
+ * required=true,
+ * @OA\Schema(
+ * type="integer",
+ * format="int64"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="API key deleted successfully",
+ * @OA\JsonContent(
+ * @OA\Property(property="message", type="string", example="API key deleted successfully"),
+ * )
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="API key not found",
+ * @OA\JsonContent(
+ * @OA\Property(property="message", type="string", example="API key not found"),
+ * )
+ * ),
+ * )
+ */
+ public function destroy($apikey_id)
+ {
+ $apiKey = ApiKey::find($apikey_id);
+
+ if (!$apiKey) {
+ return response()->json([
+ 'message' => 'API key not found',
+ ], 404);
+ }
+
+ $apiKey->delete();
+
+ return response()->json([
+ 'message' => 'API key deleted successfully',
+ ], 200);
+ }
+
+ /**
+ * @OA\Get(
+ * path="/api/api-keys",
+ * tags={"API Key"},
+ * summary="Get all API keys",
+ * description="Get all API keys",
+ * @OA\Response(
+ * response=200,
+ * description="API keys retrieved successfully",
+ * @OA\JsonContent(
+ * @OA\Property(property="message", type="string", example="API keys retrieved successfully"),
+ * )
+ * ),
+ * )
+ */
+ public function index(){
+
+ return response()->json(ApiKey::all(), 200);
+ }
+}
diff --git a/sera-back/app/Models/ApiKey.php b/sera-back/app/Models/ApiKey.php
new file mode 100644
index 0000000..e9ebf90
--- /dev/null
+++ b/sera-back/app/Models/ApiKey.php
@@ -0,0 +1,12 @@
+ ["store","destroy","index"],
"knowledges" => ["show", "index", "store", "update", "destroy", "getTypes"],
"edito" => ["show", "index", "store", "update", "destroy","removeImage","addKnowledge","removeKnowledge"],
+ "api-keys" => ["store", "recreate", "destroy","index"],
],
"project_manager" => [
"projects-requests" => ["show", "index", "update"],
@@ -30,7 +31,7 @@
"subtitles" => ["store","destroy","index"],
"knowledges" => ["show", "index", "store", "update", "destroy", "getTypes"],
"edito" => ["show", "index", "store", "update", "destroy","removeImage","addKnowledge","removeKnowledge"],
-
+ "api-keys" => ["store", "recreate", "destroy","index"],
],
"professor" => [
"users" => ["iso","show", "index", "roles", "image", "password","reservations"],
diff --git a/sera-back/database/migrations/2023_09_14_213435_create_api_keys_table.php b/sera-back/database/migrations/2023_09_14_213435_create_api_keys_table.php
new file mode 100644
index 0000000..d8abb5f
--- /dev/null
+++ b/sera-back/database/migrations/2023_09_14_213435_create_api_keys_table.php
@@ -0,0 +1,32 @@
+id();
+ $table->foreignId('user_id')->constrained()->onDelete('cascade');
+ $table->string('key');
+ $table->string('name');
+ $table->text('description')->nullable();
+ $table->timestamp('expires_at')->nullable();
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('api_keys');
+ }
+};
diff --git a/sera-back/routes/api.php b/sera-back/routes/api.php
index 94dd3bf..7e7ca75 100644
--- a/sera-back/routes/api.php
+++ b/sera-back/routes/api.php
@@ -136,6 +136,12 @@
Route::post('projects/{projectId}/edito/remove-knowledge', 'App\Http\Controllers\EditoController@unlinkKnowledge')->name('edito.removeKnowledge');
/************************/
+ /***** API Key *****/
+ Route::post('api-keys', 'App\Http\Controllers\ApiKeyController@store')->name('api-keys.store');
+ Route::post('api-keys/{apikey_id}/recreate', 'App\Http\Controllers\ApiKeyController@recreate')->name('api-keys.recreate');
+ Route::delete('api-keys/{apikey_id}', 'App\Http\Controllers\ApiKeyController@destroy')->name('api-keys.destroy');
+ Route::get('api-keys', 'App\Http\Controllers\ApiKeyController@index')->name('api-keys.index');
+
/*********************************/
diff --git a/sera-back/storage/api-docs/api-docs.json b/sera-back/storage/api-docs/api-docs.json
index 63db2e9..c481185 100644
--- a/sera-back/storage/api-docs/api-docs.json
+++ b/sera-back/storage/api-docs/api-docs.json
@@ -5,6 +5,246 @@
"version": "1.0.0"
},
"paths": {
+ "/api/api-keys": {
+ "get": {
+ "tags": [
+ "API Key"
+ ],
+ "summary": "Get all API keys",
+ "description": "Get all API keys",
+ "operationId": "48d6f21fc4f70c87bb9e0fe128fc333d",
+ "responses": {
+ "200": {
+ "description": "API keys retrieved successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "API keys retrieved successfully"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "API Key"
+ ],
+ "summary": "Create an API key",
+ "description": "Create an API key",
+ "operationId": "97fc3d21663312cdba253bcfe2bd244e",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "required": [
+ "name",
+ "expires_at",
+ "never_expires"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "My API key"
+ },
+ "description": {
+ "type": "string",
+ "example": "My API key description"
+ },
+ "expires_at": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2021-09-14T21:34:35.000000Z"
+ },
+ "never_expires": {
+ "type": "boolean",
+ "example": "false"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "API key created successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "API key created successfully"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Validation error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The given data was invalid."
+ },
+ "errors": {
+ "type": "object",
+ "example": {
+ "name": [
+ "The name field is required."
+ ]
+ }
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Unauthenticated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Unauthenticated."
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/api-keys/{apikey_id}/recreate": {
+ "post": {
+ "tags": [
+ "API Key"
+ ],
+ "summary": "Recreate an API key",
+ "description": "Recreate an API key",
+ "operationId": "c766b71c349f65f13633900bf2435acf",
+ "parameters": [
+ {
+ "name": "apikey_id",
+ "in": "path",
+ "description": "ID of the API key to recreate",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "API key recreated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "API key recreated successfully"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "API key not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "API key not found"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/api-keys/{apikey_id}": {
+ "delete": {
+ "tags": [
+ "API Key"
+ ],
+ "summary": "Delete an API key",
+ "description": "Delete an API key",
+ "operationId": "735a9edea689ca45c188b2bbbf3dbac8",
+ "parameters": [
+ {
+ "name": "apikey_id",
+ "in": "path",
+ "description": "ID of the API key to delete",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "API key deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "API key deleted successfully"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "API key not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "API key not found"
+ }
+ },
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/projects/{project_id}/edito": {
"get": {
"tags": [
From 3c2fa81aa7ed00600109ea8d197b4c5abe8aea77 Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 00:46:38 +0200
Subject: [PATCH 04/27] feat(Course): One api to get all course + one other to
show one api with a good format UwU
---
.../app/Http/Controllers/CourseController.php | 77 +++++++++++++++++++
sera-back/routes/web.php | 3 +
2 files changed, 80 insertions(+)
create mode 100644 sera-back/app/Http/Controllers/CourseController.php
diff --git a/sera-back/app/Http/Controllers/CourseController.php b/sera-back/app/Http/Controllers/CourseController.php
new file mode 100644
index 0000000..f3ef98c
--- /dev/null
+++ b/sera-back/app/Http/Controllers/CourseController.php
@@ -0,0 +1,77 @@
+select('id', 'title', 'description')
+ ->paginate(15);
+
+ return response()->json(
+ $projects,
+ 200
+ );
+ }
+
+ public function show($id)
+ {
+ $project = Project::with(['videoReviews' => function ($query) {
+ $query->where('validated', true);
+ }, 'videoReviews.ressource', 'subtitles.ressource', 'edito.knowledges'])->find($id);
+
+ if (!$project) {
+ return response()->json(['error' => 'Projet introuvable'], 404);
+ }
+
+ $json = [
+ "Title" => $project->title,
+ "Description" => $project->description,
+ "Video" => null,
+ "Subtitles" => [],
+ "Edito" => null,
+ ];
+
+ if ($project->videoReviews) {
+ $video = $project->videoReviews->first();
+ $videoRessource = $video->ressource;
+ $json["Video"] = [
+ "Name" => $videoRessource->name,
+ "Url" => $videoRessource->url,
+ "Type" => $videoRessource->type,
+ "Description" => $videoRessource->description,
+ ];
+ }
+
+ foreach ($project->subtitles as $subtitle) {
+ $subtitleRessource = $subtitle->ressource;
+ $json["Subtitles"][$subtitle->lang] = $subtitleRessource->url;
+ }
+
+ if ($project->edito) {
+ $edito = $project->edito;
+ $editoJson = [
+ "Title" => $edito->title,
+ "Description" => $edito->description,
+ "Knowledges" => $edito->knowledges->map(function ($knowledge) {
+ return [
+ "Name" => $knowledge->name,
+ "Infos" => $knowledge->infos,
+ "Image" => $knowledge->image,
+ "Type" => $knowledge->type,
+ ];
+ }),
+ "Images" => $edito->images,
+ ];
+ $json["Edito"] = $editoJson;
+ }
+
+ return response()->json($json, 200);
+ }
+
+}
diff --git a/sera-back/routes/web.php b/sera-back/routes/web.php
index 2a4a443..466f8df 100644
--- a/sera-back/routes/web.php
+++ b/sera-back/routes/web.php
@@ -18,6 +18,9 @@
});
+Route::get('/courses', 'App\Http\Controllers\CourseController@index')->name('courses.index');
+Route::get('/courses/{course}', 'App\Http\Controllers\CourseController@show')->name('courses.show');
+
// Route::get('/test', 'App\Http\Controllers\UserController@test')->name('test');
require __DIR__.'/auth.php';
From 6026fd5ac40c31e56ee9d7ad2f2dd639d95bf8c4 Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 00:56:48 +0200
Subject: [PATCH 05/27] feat(Course): Middleware to check the api_key before
request ~_~
---
sera-back/app/Http/Middleware/ApiCheck.php | 36 ++++++++++++++++++++++
sera-back/app/Models/ApiKey.php | 1 +
sera-back/routes/web.php | 5 +--
3 files changed, 40 insertions(+), 2 deletions(-)
create mode 100644 sera-back/app/Http/Middleware/ApiCheck.php
diff --git a/sera-back/app/Http/Middleware/ApiCheck.php b/sera-back/app/Http/Middleware/ApiCheck.php
new file mode 100644
index 0000000..c9b7aec
--- /dev/null
+++ b/sera-back/app/Http/Middleware/ApiCheck.php
@@ -0,0 +1,36 @@
+header('api_token');
+ // on vérifie que le token existe
+ if (!$token) {
+ // si le token n'existe pas, on retourne une erreur 401
+ return response()->json(['error' => 'Unauthorized, no token provided'], 401);
+ }
+ // on vérifie que le token existe dans la table api_keys
+ $apiKey = ApiKey::where('key', $token)->first();
+
+ if (!$apiKey) {
+ // si le token n'existe pas, on retourne une erreur 401
+ return response()->json(['error' => 'Unauthorized, invalid token'], 401);
+ }
+
+ return $next($request);
+ }
+}
diff --git a/sera-back/app/Models/ApiKey.php b/sera-back/app/Models/ApiKey.php
index e9ebf90..4906202 100644
--- a/sera-back/app/Models/ApiKey.php
+++ b/sera-back/app/Models/ApiKey.php
@@ -9,4 +9,5 @@ class ApiKey extends Model
{
use HasFactory;
+
}
diff --git a/sera-back/routes/web.php b/sera-back/routes/web.php
index 466f8df..46b1831 100644
--- a/sera-back/routes/web.php
+++ b/sera-back/routes/web.php
@@ -1,5 +1,6 @@
app()->version()];
});
+Route::get('/courses', 'App\Http\Controllers\CourseController@index')->name('courses.index')->middleware(ApiCheck::class);
+Route::get('/courses/{course}', 'App\Http\Controllers\CourseController@show')->name('courses.show')->middleware(ApiCheck::class);
-Route::get('/courses', 'App\Http\Controllers\CourseController@index')->name('courses.index');
-Route::get('/courses/{course}', 'App\Http\Controllers\CourseController@show')->name('courses.show');
// Route::get('/test', 'App\Http\Controllers\UserController@test')->name('test');
From 01480b9896866c68a8b392e254d85240712b64ba Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 01:03:06 +0200
Subject: [PATCH 06/27] chore(Course): Doc + local env remove restriction
---
.../app/Http/Controllers/CourseController.php | 48 +++++++++++++++++
sera-back/app/Http/Middleware/ApiCheck.php | 6 +++
sera-back/storage/api-docs/api-docs.json | 51 +++++++++++++++++++
3 files changed, 105 insertions(+)
diff --git a/sera-back/app/Http/Controllers/CourseController.php b/sera-back/app/Http/Controllers/CourseController.php
index f3ef98c..013aa8a 100644
--- a/sera-back/app/Http/Controllers/CourseController.php
+++ b/sera-back/app/Http/Controllers/CourseController.php
@@ -7,6 +7,23 @@
class CourseController extends Controller
{
+ /**
+ * @OA\Get(
+ * path="/courses",
+ * operationId="getCourseList",
+ * tags={"Courses"},
+ * summary="Get list of courses",
+ * description="Returns list of courses",
+ * @OA\Response(
+ * response=200,
+ * description="successful operation",
+ * ),
+ * @OA\Response(
+ * response=401,
+ * description="Unauthorized",
+ * ),
+ * )
+ */
public function index()
{
$projects = Project::where('status', 'published')
@@ -19,6 +36,37 @@ public function index()
);
}
+ /**
+ * @OA\Get(
+ * path="/courses/{id}",
+ * operationId="getCourseById",
+ * tags={"Courses"},
+ * summary="Get course information",
+ * description="Returns course data",
+ * @OA\Parameter(
+ * name="id",
+ * description="Course id",
+ * required=true,
+ * in="path",
+ * @OA\Schema(
+ * type="integer",
+ * format="int64"
+ * )
+ * ),
+ * @OA\Response(
+ * response=200,
+ * description="successful operation",
+ * ),
+ * @OA\Response(
+ * response=401,
+ * description="Unauthorized",
+ * ),
+ * @OA\Response(
+ * response=404,
+ * description="Not found",
+ * ),
+ * )
+ */
public function show($id)
{
$project = Project::with(['videoReviews' => function ($query) {
diff --git a/sera-back/app/Http/Middleware/ApiCheck.php b/sera-back/app/Http/Middleware/ApiCheck.php
index c9b7aec..06a3780 100644
--- a/sera-back/app/Http/Middleware/ApiCheck.php
+++ b/sera-back/app/Http/Middleware/ApiCheck.php
@@ -16,6 +16,12 @@ class ApiCheck
*/
public function handle(Request $request, Closure $next): Response
{
+
+ // si l'appel est fait en local, on ne vérifie pas le token
+ if (env('APP_ENV') === 'local') {
+ return $next($request);
+ }
+
// on récupère le token appelé "api_token" dans le header de la requête
$token = $request->header('api_token');
// on vérifie que le token existe
diff --git a/sera-back/storage/api-docs/api-docs.json b/sera-back/storage/api-docs/api-docs.json
index c481185..e7ebb76 100644
--- a/sera-back/storage/api-docs/api-docs.json
+++ b/sera-back/storage/api-docs/api-docs.json
@@ -245,6 +245,57 @@
}
}
},
+ "/courses": {
+ "get": {
+ "tags": [
+ "Courses"
+ ],
+ "summary": "Get list of courses",
+ "description": "Returns list of courses",
+ "operationId": "getCourseList",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ },
+ "401": {
+ "description": "Unauthorized"
+ }
+ }
+ }
+ },
+ "/courses/{id}": {
+ "get": {
+ "tags": [
+ "Courses"
+ ],
+ "summary": "Get course information",
+ "description": "Returns course data",
+ "operationId": "getCourseById",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "description": "Course id",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ },
+ "401": {
+ "description": "Unauthorized"
+ },
+ "404": {
+ "description": "Not found"
+ }
+ }
+ }
+ },
"/api/projects/{project_id}/edito": {
"get": {
"tags": [
From 10cc220a1eae57522253fd8415dfc9e493fd55b6 Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 01:30:56 +0200
Subject: [PATCH 07/27] feat(ApiKey): Seeders for each cursus director
---
.../database/factories/ApiKeyFactory.php | 25 ++++++++++++++++++
sera-back/database/seeders/ApiKey.php | 26 +++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 sera-back/database/factories/ApiKeyFactory.php
create mode 100644 sera-back/database/seeders/ApiKey.php
diff --git a/sera-back/database/factories/ApiKeyFactory.php b/sera-back/database/factories/ApiKeyFactory.php
new file mode 100644
index 0000000..ec9ec85
--- /dev/null
+++ b/sera-back/database/factories/ApiKeyFactory.php
@@ -0,0 +1,25 @@
+
+ */
+class ApiKeyFactory extends Factory
+{
+ /**
+ * Define the model's default state.
+ *
+ * @return array
+ */
+ public function definition(): array
+ {
+ return [
+ 'key' => $this->faker->uuid(),
+ 'name' => $this->faker->word(),
+ 'description' => $this->faker->sentence(),
+ ];
+ }
+}
diff --git a/sera-back/database/seeders/ApiKey.php b/sera-back/database/seeders/ApiKey.php
new file mode 100644
index 0000000..488236a
--- /dev/null
+++ b/sera-back/database/seeders/ApiKey.php
@@ -0,0 +1,26 @@
+get();
+ foreach ($users as $user) {
+ \App\Models\ApiKey::factory()->count(1)->create([
+ 'user_id' => $user->id,
+ ]);
+ }
+
+
+
+ }
+}
From 16ab83f3531ec51e6e141c5224ce14a128f42193 Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 01:32:55 +0200
Subject: [PATCH 08/27] =?UTF-8?q?feat:=20Add=20api=20to=20seeders=20?=
=?UTF-8?q?=E2=98=86*:=20.=EF=BD=A1.=20o(=E2=89=A7=E2=96=BD=E2=89=A6)o=20.?=
=?UTF-8?q?=EF=BD=A1.:*=E2=98=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sera-back/database/seeders/DatabaseSeeder.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/sera-back/database/seeders/DatabaseSeeder.php b/sera-back/database/seeders/DatabaseSeeder.php
index 8bf18a8..5006890 100644
--- a/sera-back/database/seeders/DatabaseSeeder.php
+++ b/sera-back/database/seeders/DatabaseSeeder.php
@@ -26,6 +26,7 @@ public function run(): void
// VideoReviewSeeder::class,
NotificationSeeder::class,
KnowledgeSeeder::class,
+ ApiKey::class,
]);
}
}
From cdf76dec05a879164f2e6a792345783effb46ccf Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 01:50:46 +0200
Subject: [PATCH 09/27] fix: sedder project8 for edito part UwU
---
sera-back/database/seeders/ProjectSeeder.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/sera-back/database/seeders/ProjectSeeder.php b/sera-back/database/seeders/ProjectSeeder.php
index e8f803a..f8a5e15 100644
--- a/sera-back/database/seeders/ProjectSeeder.php
+++ b/sera-back/database/seeders/ProjectSeeder.php
@@ -231,6 +231,7 @@ public function run(): void
$project->steps->{'Post-Production'}->status = 'done';
$project->steps->{'Transcription'}->status = 'done';
$project->steps->{'Subtitling'}->status = 'ongoing';
+ $project->steps->{'Editorial'}->status = 'ongoing';
$project->steps = json_encode($project->steps);
$project->save();
From f243b4c4f4b61e64997bf1a056e7e5a3ecc8ceae Mon Sep 17 00:00:00 2001
From: Adrien Albuquerque
Date: Fri, 15 Sep 2023 01:46:33 +0200
Subject: [PATCH 10/27] =?UTF-8?q?fix(ApiKey):=20Remove=20key=20from=20inde?=
=?UTF-8?q?x=20response=20(=F0=9F=91=89=EF=BE=9F=E3=83=AE=EF=BE=9F)?=
=?UTF-8?q?=F0=9F=91=89=F0=9F=91=88(=EF=BE=9F=E3=83=AE=EF=BE=9F?=
=?UTF-8?q?=F0=9F=91=88)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sera-back/app/Http/Controllers/ApiKeyController.php | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sera-back/app/Http/Controllers/ApiKeyController.php b/sera-back/app/Http/Controllers/ApiKeyController.php
index ed929df..0c378f1 100644
--- a/sera-back/app/Http/Controllers/ApiKeyController.php
+++ b/sera-back/app/Http/Controllers/ApiKeyController.php
@@ -188,7 +188,8 @@ public function destroy($apikey_id)
* )
*/
public function index(){
-
- return response()->json(ApiKey::all(), 200);
+ // get all api keys but remove key from the response
+ $apiKeys = ApiKey::all()->makeHidden('key');
+ return response()->json($apiKeys, 200);
}
}
From 19c20c654972835c51c92c6ea19ce459fb99ef49 Mon Sep 17 00:00:00 2001
From: Antoine Azevedo Da Silva
Date: Thu, 14 Sep 2023 20:19:11 +0200
Subject: [PATCH 11/27] feat(apikeys): create ApiKey page
- create routes
- restriction access
- The page & modals
---
.../src/components/app/apiKey/ApiKeyModal.tsx | 79 +++++++++++++++++++
.../src/components/app/apiKey/ApiKeyTable.tsx | 69 ++++++++++++++++
.../src/components/app/navigation/Nav.tsx | 19 +++++
.../Reservation/ReservationContainer.tsx | 43 +---------
sera-front/src/components/ui/datePicker.tsx | 41 ++++++++++
sera-front/src/lib/routes.tsx | 5 ++
sera-front/src/lib/utils.ts | 23 ++----
sera-front/src/pages/ApiKey.tsx | 68 ++++++++++++++++
8 files changed, 291 insertions(+), 56 deletions(-)
create mode 100644 sera-front/src/components/app/apiKey/ApiKeyModal.tsx
create mode 100644 sera-front/src/components/app/apiKey/ApiKeyTable.tsx
create mode 100644 sera-front/src/components/ui/datePicker.tsx
create mode 100644 sera-front/src/pages/ApiKey.tsx
diff --git a/sera-front/src/components/app/apiKey/ApiKeyModal.tsx b/sera-front/src/components/app/apiKey/ApiKeyModal.tsx
new file mode 100644
index 0000000..56d40b0
--- /dev/null
+++ b/sera-front/src/components/app/apiKey/ApiKeyModal.tsx
@@ -0,0 +1,79 @@
+import { useState } from "react";
+
+import { Button } from "@/components/ui/button";
+import { DatePicker } from "@/components/ui/datePicker";
+import {
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+} from "@/components/ui/dialog";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+
+export const AddKeyDialog = () => {
+ const [apiKey, setApiKey] = useState("");
+ const [keyName, setKeyName] = useState("");
+ const [keyDescription, setKeyDescription] = useState("");
+ const [keyExpiration, setKeyExpiration] = useState();
+
+ if (apiKey && apiKey != "") {
+ return <>>;
+ }
+
+ return (
+
+
+
+ Create a new API key
+
+
+
+ Generate a new API key to use with the Sera API.
+
+
+
+
+
+
+
+
+ setKeyName(e.target.value)}
+ />
+
+
+
+ setKeyDescription(e.target.value)}
+ />
+
+
+
+
+
+
+ );
+};
diff --git a/sera-front/src/components/app/apiKey/ApiKeyTable.tsx b/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
new file mode 100644
index 0000000..95bc193
--- /dev/null
+++ b/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
@@ -0,0 +1,69 @@
+import { TrashIcon } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import { convertDateFromDateType } from "@/lib/utils";
+
+export const ApiKeyTable = ({ data }: { data: any }) => {
+ return (
+
+
+
+
+ API Key name
+
+
+ API Key description
+
+
+ API Key expiration
+
+
+ Action
+
+
+
+
+ {console.log(data, data.length, data.length > 0)}
+ {data &&
+ data.length > 0 &&
+ data.map((keyElement: any) => {
+ return (
+
+
+ {keyElement.name}
+
+
+ {keyElement.description}
+
+
+ {convertDateFromDateType(keyElement.expiration)}
+
+
+
+
+
+ );
+ })}
+
+
+ );
+};
diff --git a/sera-front/src/components/app/navigation/Nav.tsx b/sera-front/src/components/app/navigation/Nav.tsx
index 81d8f19..d0633cc 100644
--- a/sera-front/src/components/app/navigation/Nav.tsx
+++ b/sera-front/src/components/app/navigation/Nav.tsx
@@ -4,6 +4,7 @@ import {
DoorOpen,
FolderOpen,
Home,
+ KeyRound,
Ticket,
User,
WalletCards,
@@ -144,6 +145,24 @@ export const Nav = () => {
Projects
+
+ {accessManager("api", undefined) && (
+
+
+
+ API Keys
+
+
+ )}
);
diff --git a/sera-front/src/components/app/project/Reservation/ReservationContainer.tsx b/sera-front/src/components/app/project/Reservation/ReservationContainer.tsx
index 6f1241b..552db9a 100644
--- a/sera-front/src/components/app/project/Reservation/ReservationContainer.tsx
+++ b/sera-front/src/components/app/project/Reservation/ReservationContainer.tsx
@@ -3,7 +3,6 @@ import clsx from "clsx";
import {
ArrowLeft,
ArrowRight,
- CalendarIcon,
Clapperboard,
PenBox,
Plus,
@@ -13,7 +12,7 @@ import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { Button } from "@/components/ui/button";
-import { Calendar } from "@/components/ui/calendar";
+import { DatePicker } from "@/components/ui/datePicker";
import {
Dialog,
DialogContent,
@@ -24,20 +23,9 @@ import {
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
import { Separator } from "@/components/ui/separator";
import { axios } from "@/lib/axios";
-import {
- accessManager,
- cn,
- convertDate,
- convertDateFromDateType,
- selectRoleDisplay,
-} from "@/lib/utils";
+import { accessManager, convertDate, selectRoleDisplay } from "@/lib/utils";
import { BigLoader } from "@/pages/skeletons/BigLoader";
export const ReservationContainer = ({
@@ -516,30 +504,3 @@ const SearchRoomDialog = ({
);
};
-
-const DatePicker = ({ date, setDate }: any) => {
- return (
-
-
-
-
-
-
-
-
- );
-};
diff --git a/sera-front/src/components/ui/datePicker.tsx b/sera-front/src/components/ui/datePicker.tsx
new file mode 100644
index 0000000..13c467b
--- /dev/null
+++ b/sera-front/src/components/ui/datePicker.tsx
@@ -0,0 +1,41 @@
+import { CalendarIcon } from "lucide-react";
+
+import { cn, convertDateFromDateType } from "@/lib/utils";
+
+import { Button } from "./button";
+import { Calendar } from "./calendar";
+import { Popover, PopoverContent, PopoverTrigger } from "./popover";
+
+export const DatePicker = ({ date, setDate, hideToday = false }: any) => {
+ const today = new Date();
+
+ if (hideToday) {
+ today.setDate(today.getDate() + 1);
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/sera-front/src/lib/routes.tsx b/sera-front/src/lib/routes.tsx
index f59aa3c..6b3ac42 100644
--- a/sera-front/src/lib/routes.tsx
+++ b/sera-front/src/lib/routes.tsx
@@ -1,5 +1,6 @@
import { createBrowserRouter, Navigate } from "react-router-dom";
+import { ApiKey } from "@/pages/ApiKey";
import App from "@/pages/App";
import { Capture } from "@/pages/Capture";
import { Error404 } from "@/pages/Error404";
@@ -28,6 +29,10 @@ const paths = [
index: true,
element: ,
},
+ {
+ path: "api",
+ element: ,
+ },
{
path: "rooms",
element: ,
diff --git a/sera-front/src/lib/utils.ts b/sera-front/src/lib/utils.ts
index 6417ac3..aecf7b6 100644
--- a/sera-front/src/lib/utils.ts
+++ b/sera-front/src/lib/utils.ts
@@ -253,26 +253,23 @@ export const accessManager = (page?: string, action?: string) => {
if (role === "cursus_director") return true;
if (role === "project_manager") {
- //Project request
+ if (page === "api") return false;
+
if (action === "add_project_request") return false;
if (action === "delete_project_request") return false;
-
- //Project
if (action === "validate_project_step") return true;
-
- //Rooms
if (action === "add_room") return false;
if (action === "edit_room") return false;
if (action === "delete_room") return false;
}
if (role === "professor") {
+ if (page === "api") return false;
if (page === "users") return false;
if (page === "rooms") return false;
if (page === "project_requests") return false;
if (page === "knowledge_base") return false;
- //Project
if (action === "validate_project_step") return false;
if (action === "remove_project_team_member") return false;
if (action === "add_project_team_member") return false;
@@ -287,12 +284,12 @@ export const accessManager = (page?: string, action?: string) => {
}
if (role === "video_team") {
+ if (page === "api") return false;
if (page === "users") return false;
if (page === "rooms") return false;
if (page === "project_requests") return false;
if (page === "knowledge_base") return false;
- //Project
if (action === "validate_project_step") return false;
if (action === "remove_project_team_member") return false;
if (action === "add_project_team_member") return false;
@@ -307,12 +304,12 @@ export const accessManager = (page?: string, action?: string) => {
}
if (role === "video_editor") {
+ if (page === "api") return false;
if (page === "users") return false;
if (page === "rooms") return false;
if (page === "project_requests") return false;
if (page === "knowledge_base") return false;
- //Project
if (action === "validate_project_step") return false;
if (action === "remove_project_team_member") return false;
if (action === "add_project_team_member") return false;
@@ -327,12 +324,12 @@ export const accessManager = (page?: string, action?: string) => {
}
if (role === "transcription_team") {
+ if (page === "api") return false;
if (page === "users") return false;
if (page === "rooms") return false;
if (page === "project_requests") return false;
if (page === "knowledge_base") return false;
- //Project
if (action === "validate_project_step") return false;
if (action === "remove_project_team_member") return false;
if (action === "add_project_team_member") return false;
@@ -342,17 +339,15 @@ export const accessManager = (page?: string, action?: string) => {
if (action === "add_professor_notes") return false;
if (action === "add_video_version") return false;
if (action === "add_subs") return false;
-
- //Ajouter pr l'edito et les subs
}
if (role === "traduction_team") {
+ if (page === "api") return false;
if (page === "users") return false;
if (page === "rooms") return false;
if (page === "project_requests") return false;
if (page === "knowledge_base") return false;
- //Project
if (action === "validate_project_step") return false;
if (action === "remove_project_team_member") return false;
if (action === "add_project_team_member") return false;
@@ -362,17 +357,15 @@ export const accessManager = (page?: string, action?: string) => {
if (action === "add_professor_notes") return false;
if (action === "add_video_version") return false;
if (action === "add_transcript") return false;
-
- //Ajouter pr l'edito et les subs
}
if (role === "editorial_team") {
+ if (page === "api") return false;
if (page === "users") return false;
if (page === "rooms") return false;
if (page === "project_requests") return false;
if (page === "knowledge_base") return false;
- //Project
if (action === "validate_project_step") return false;
if (action === "remove_project_team_member") return false;
if (action === "add_project_team_member") return false;
diff --git a/sera-front/src/pages/ApiKey.tsx b/sera-front/src/pages/ApiKey.tsx
new file mode 100644
index 0000000..ca81666
--- /dev/null
+++ b/sera-front/src/pages/ApiKey.tsx
@@ -0,0 +1,68 @@
+import { useEffect, useState } from "react";
+import { useNavigate, useSearchParams } from "react-router-dom";
+
+import { AddKeyDialog } from "@/components/app/apiKey/ApiKeyModal";
+import { ApiKeyTable } from "@/components/app/apiKey/ApiKeyTable";
+import { Button } from "@/components/ui/button";
+import { Dialog } from "@/components/ui/dialog";
+import { accessManager } from "@/lib/utils";
+
+export const ApiKey = () => {
+ const navigate = useNavigate();
+ const [searchParams] = useSearchParams();
+ const [addApiKeyDialog, setAddApiKeyDialog] = useState(false);
+
+ useEffect(() => {
+ if (!accessManager("api", undefined)) {
+ return navigate("/dashboard");
+ }
+
+ if (searchParams.get("action") || addApiKeyDialog) {
+ navigate("/dashboard/api?action=add");
+ setAddApiKeyDialog(true);
+ }
+ }, [addApiKeyDialog]);
+
+ return (
+
+
+
API Keys
+
+ {accessManager(undefined, "add_api_key") && (
+
+ )}
+
+
+
+
+
+
+
+ );
+};
+
+const data = [
+ {
+ name: "test",
+ description: "test",
+ expiration: new Date("2023-08-01"),
+ },
+ {
+ name: "API key for the website 1",
+ description: "API key for the website 1",
+ expiration: new Date("2023-12-01"),
+ },
+];
From a358ef9b2dcc62847f2d651b85031d246480d13a Mon Sep 17 00:00:00 2001
From: Antoine Azevedo Da Silva
Date: Thu, 14 Sep 2023 22:08:08 +0200
Subject: [PATCH 12/27] feat: added support action with specific key
---
.../src/components/app/apiKey/ApiKeyTable.tsx | 21 ++++++++-----------
sera-front/src/lib/routes.tsx | 6 ++++++
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/sera-front/src/components/app/apiKey/ApiKeyTable.tsx b/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
index 95bc193..b172f27 100644
--- a/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
+++ b/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
@@ -1,6 +1,6 @@
-import { TrashIcon } from "lucide-react";
+import { RefreshCw, Trash } from "lucide-react";
+import { Link } from "react-router-dom";
-import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
@@ -49,16 +49,13 @@ export const ApiKeyTable = ({ data }: { data: any }) => {
{convertDateFromDateType(keyElement.expiration)}
-
-
+
+
+
+
+
+
+
);
diff --git a/sera-front/src/lib/routes.tsx b/sera-front/src/lib/routes.tsx
index 6b3ac42..9338278 100644
--- a/sera-front/src/lib/routes.tsx
+++ b/sera-front/src/lib/routes.tsx
@@ -32,6 +32,12 @@ const paths = [
{
path: "api",
element: ,
+ children: [
+ {
+ path: ":keyId",
+ element: ,
+ },
+ ],
},
{
path: "rooms",
From eacd94055d7933b98583115b4e9c3c34f94cc291 Mon Sep 17 00:00:00 2001
From: Antoine Azevedo Da Silva
Date: Thu, 14 Sep 2023 22:42:16 +0200
Subject: [PATCH 13/27] fix: wrong key in map
---
sera-front/src/components/app/apiKey/ApiKeyTable.tsx | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/sera-front/src/components/app/apiKey/ApiKeyTable.tsx b/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
index b172f27..89a8737 100644
--- a/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
+++ b/sera-front/src/components/app/apiKey/ApiKeyTable.tsx
@@ -31,13 +31,12 @@ export const ApiKeyTable = ({ data }: { data: any }) => {
- {console.log(data, data.length, data.length > 0)}
{data &&
data.length > 0 &&
- data.map((keyElement: any) => {
+ data.map((keyElement: any, index: number) => {
return (
From 5aaacf15254db4fb2a11e7cb22a6b2a58c816dc1 Mon Sep 17 00:00:00 2001
From: Antoine Azevedo Da Silva
Date: Thu, 14 Sep 2023 22:42:35 +0200
Subject: [PATCH 14/27] feat: create renew & delete modal
---
.../src/components/app/apiKey/ApiKeyModal.tsx | 72 +++++++++++++++++--
1 file changed, 67 insertions(+), 5 deletions(-)
diff --git a/sera-front/src/components/app/apiKey/ApiKeyModal.tsx b/sera-front/src/components/app/apiKey/ApiKeyModal.tsx
index 56d40b0..56358af 100644
--- a/sera-front/src/components/app/apiKey/ApiKeyModal.tsx
+++ b/sera-front/src/components/app/apiKey/ApiKeyModal.tsx
@@ -7,6 +7,7 @@ import {
DialogDescription,
DialogFooter,
DialogHeader,
+ DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -24,13 +25,14 @@ export const AddKeyDialog = () => {
return (
-
+
Create a new API key
-
+
+
+ Generate a new API key to use with the Sera API.
+
-
- Generate a new API key to use with the Sera API.
-
+