Skip to content

Commit

Permalink
[#34722] Add Authentication and Authorization to api routes (#90)
Browse files Browse the repository at this point in the history
* initial sanctum setup and concept api controller protection

* add sanctum middleware to api group, update controllers to protect routes, update axios bootstrapping

* add reconcile to methods allowed on concept controller without auth

* add role and permission models to application

* update isVocabularyEditor to use Permission model

* [#34722] add phpunit cache to gitignore

* [#34722] Scaffold out Concepts Authorization

* feat: Set up authorization for Concept model using policies and tests

* update user factory for Laravel 11

* fix: Clean up example tests and concept test, simplify concept api controller

* feat: Factories and model bindings for Term, Concept, and User

* formatting fix

* feat: Working concept testing

* feat: Create interactive artisan command to add user with role

* chore: concepts api controller comment cleanup

* feat: Add TermPolicy for managing terms and conditions access

* feat: Add authorization for Term API in policy and controller

* refactor: Update TermController to use type hinting for Term model

* fix: update return status for concept deletion

* feat: Add Term API testing

* refactor: Update TermController authorization

* feat: Add resource authorization to ConceptSourceController

* refactor: Update method signatures to type hint ConceptSource model

* feat: Add ConceptSources API testing

* fix: Update type hinting to use correct variable name
  • Loading branch information
nevinsm authored Oct 23, 2024
1 parent ae42e9b commit 376a4be
Show file tree
Hide file tree
Showing 35 changed files with 1,280 additions and 154 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_DOMAIN=.ddev.site

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.env
.env.backup
.phpunit.result.cache
.phpunit.cache
Homestead.json
Homestead.yaml
npm-debug.log
Expand Down
39 changes: 39 additions & 0 deletions app/Console/Commands/AddUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\User;
use App\Models\Role;

class AddUser extends Command
{
protected $signature = 'user:add';

protected $description = 'Add a new user with a role';

public function handle()
{
$firstName = $this->ask('Enter the user\'s first name');
$lastName = $this->ask('Enter the user\'s last name');
$email = $this->ask('Enter the user\'s email');

// Fetch available roles
$roles = Role::all()->pluck('label')->toArray();
$role = $this->choice('Select a role for the user', $roles);

// Create the user
$user = User::create([
'first' => $firstName,
'last' => $lastName,
'fullname' => "{$firstName} {$lastName}",
'email' => $email,
'username' => $email,
]);

// Assign the role to the user
$user->assignRole($role); // Ensure you have a method to assign roles

$this->info("User {$firstName} {$lastName} with role {$role} has been created successfully.");
}
}
2 changes: 1 addition & 1 deletion app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
//
\App\Console\Commands\AddUser::class,
];

/**
Expand Down
86 changes: 67 additions & 19 deletions app/Http/Controllers/API/ConceptController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@

class ConceptController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:sanctum')->except(['index', 'show', 'reconcile']);
$this->authorizeResource(Concept::class);
}

/**
* Display a listing of the resource.
*
Expand Down Expand Up @@ -102,7 +113,7 @@ public function store(ConceptStoreRequest $request)
DB::commit();
return response()->json([
"id" => $concept->id,
]);
], 201);
} catch (\Throwable $th) {
DB::rollback();

Expand All @@ -116,24 +127,23 @@ public function store(ConceptStoreRequest $request)
/**
* Display the specified resource.
*
* @param int $id
* @param \App\Concept $concept
* @return \Illuminate\Http\Response
*/
public function show($id)
public function show(Concept $concept)
{
return Concept::findOrFail($id);
return $concept;
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @param \App\Concept $concept
* @return \Illuminate\Http\Response
*/
public function update(Request $request, int $id)
public function update(Request $request, Concept $concept)
{
$concept = Concept::findOrFail($id);
$attributes = $request->all();

// Sync concept categories
Expand All @@ -152,15 +162,50 @@ public function update(Request $request, int $id)
return new Response($concept);
}

/**
* Relate Concepts
*
* @param \Illuminate\Http\Request $request
* @param \App\Concept $concept
* @return \Illuminate\Http\Response
*/
public function relateConcepts(Request $request, Concept $concept)
{
if ($request->user()->cannot('update', $concept)) {
abort(403);
}

$relation_type = $request->input('relation_type');
$related_id = $request->input('related_id');

switch ($relation_type) {
case "broader":
$concept->addBroader($related_id);
break;
case "narrower":
$concept->addNarrower($related_id);
break;
case "related":
$concept->addRelated($related_id);
break;
}

return $concept;
}

/**
* Display the specified resource.
*
* @param int $id
* @param \Illuminate\Http\Request $request
* @param \App\Concept $concept
* @return \Illuminate\Http\Response
*/
public function deprecate(Request $request, $id)
public function deprecate(Request $request, Concept $concept)
{
$concept = Concept::findOrFail($id);
if ($request->user()->cannot('update', $concept)) {
abort(403);
}

$to = $request->input('to');
if ($to) {
$replaceConcept = Concept::findOrFail($to);
Expand All @@ -169,18 +214,23 @@ public function deprecate(Request $request, $id)
$concept->deprecated = !$concept->deprecated;
$concept->save();
}
return $concept->deprecated ? 'true' : 'false';

return response()->json($concept, 200);
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @param \App\Concept $concept
* @return \Illuminate\Http\Response
*/
public function destroy($id)
public function destroy(Concept $concept)
{
//
$concept->conceptCategories()->detach();
$concept->terms()->delete();
$concept->delete();

return response('Deleted ' . $concept->id, 204);
}

/**
Expand All @@ -199,11 +249,9 @@ public function reconcile(Request $request)
'category' => 'required',
]);

if (isset($request['category'])) {
$category_id = config('cache.category_ids')[$request['category']] ?? null;
$category = isset($category_id) ? $request['category'] : null;
}
$term = $_GET["term"];
$category_id = config('cache.category_ids')[$request->input('category')] ?? null;
$category = $category_id ? $request->input('category') : null;
$term = $request->input('term');

$terms = DB::table('concepts')->select('concepts.id as id', 'text as name')
->addSelect(DB::raw("true as match, 100 as score, '$category' as type"))
Expand Down
34 changes: 22 additions & 12 deletions app/Http/Controllers/API/ConceptSourceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@

class ConceptSourceController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:sanctum')->except(['index', 'show']);
$this->authorizeResource(ConceptSource::class);
}

/**
* Display a listing of the resource.
*
Expand Down Expand Up @@ -62,37 +73,36 @@ public function store(Request $request)
/**
* Display the specified resource.
*
* @param int $id
* @param ConceptSource $conceptSource
* @return \Illuminate\Http\Response
*/
public function show($id)
public function show(ConceptSource $conceptSource)
{
return ConceptSource::findOrFail($id);
return $conceptSource;
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @param ConceptSource $conceptSource
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(Request $request, ConceptSource $conceptSource)
{
$source = ConceptSource::findOrFail($id);
$source->update($request->all());
return $source;
$conceptSource->update($request->all());
return $conceptSource;
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @param ConceptSource $conceptSource
* @return \Illuminate\Http\Response
*/
public function destroy($id)
public function destroy(ConceptSource $conceptSource)
{
$source = ConceptSource::findOrFail($id)->delete();
return response('Deleted' . $id, 204);
$conceptSource->delete();
return response('Deleted ' . $conceptSource->id, 204);
}
}
32 changes: 21 additions & 11 deletions app/Http/Controllers/API/TermController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@

class TermController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:sanctum')->except(['index', 'show']);
$this->authorizeResource(Term::class);
}

/**
* Display a listing of the resource.
*
Expand Down Expand Up @@ -54,38 +65,37 @@ public function store(Request $request)
/**
* Display the specified resource.
*
* @param int $id
* @param \App\Models\Term $term
* @return \Illuminate\Http\Response
*/
public function show($id)
public function show(Term $term)
{
return Term::findOrFail($id);
return $term;
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @param \App\Models\Term $term
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(Request $request, Term $term)
{
$term = Term::findOrFail($id);
$term->update($request->all());
return $term;
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @param \App\Models\Term $term
* @return \Illuminate\Http\Response
*/
public function destroy($id)
public function destroy(Term $term)
{
$term = Term::findOrFail($id)->delete();
return response('Deleted', 204);

$term->delete();

return response('Deleted ' . $term->id, 204);
}
}
29 changes: 0 additions & 29 deletions app/Http/Controllers/ConceptController.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,33 +223,4 @@ public function search(Concept $concept)

return $terms->get();
}

/**
* Relate Concepts
*
* @param \App\Concept $concept
* @return \Illuminate\Http\Response
*/
public function relateConcepts($concept_id)
{
$relation_type = $_GET["relation_type"];
$related_id = $_GET["related_id"];

$concept = Concept::findOrFail($concept_id);

switch ($relation_type) {
case "broader":
$concept->addBroader($related_id);
break;
case "narrower":
$concept->addNarrower($related_id);
break;
case "related":
$concept->addRelated($related_id);
break;
}

return $concept;
}

}
Loading

0 comments on commit 376a4be

Please sign in to comment.