diff --git a/app/Helpers/InstitutionHelper.php b/app/Helpers/InstitutionHelper.php index b618ce0..7ade956 100644 --- a/app/Helpers/InstitutionHelper.php +++ b/app/Helpers/InstitutionHelper.php @@ -4,9 +4,44 @@ use Illuminate\Http\Request; use Carbon\Carbon; use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\DB; + +use TokenHelper; class InstitutionHelper -{ +{ + // This calls the API endpoint that checks if the current self user has been allowlisted in any institution's email lists. + // Returns the institution id, access_type of the current user if set anywhere. + public static function checkSelfInst(Request $request) { + [$tok, $tokErr] = TokenHelper::GetToken($request); + if ($tok == "") { + return ["","", $tokErr]; + } + + $headers = [ + 'Authorization' => 'Bearer '.$tok, + 'accept' => 'application/json', + 'Cache-Control' => 'no-cache', + ]; + + $resp = Http::withHeaders($headers)->get(env('BACKEND_URL').'/check_self'); + if ($resp->getStatusCode() != 200 ) { + $errMsg = json_decode($resp->getBody()); + if ($errMsg == null) { + return ["","", $resp->getStatusCode()]; + } + return ["","", $resp->getStatusCode().": ".$errMsg->detail]; + } + + $affected = DB::table('users') + ->where('email', $request->user()->email) + ->update(['access_type' => $resp["access_type"], 'inst_id' => $resp["inst_id"]]); + if ($affected != 1) { + return ["", "", "Error: User table update affected ".$affected." rows. 1 affected row expected."]; + } + return [$resp["inst_id"], $resp["access_type"], ""]; + } + // Returns the institution id and an error if any, as a tuple. public static function getInstitution(Request $request) { @@ -20,7 +55,14 @@ public static function getInstitution(Request $request) // Datakinder with no institution has to set their institution otherwise we will return an error return ["", "Datakinder must set an institution to proceed."]; } - return ["", "No institution set for this user."]; + + // Call check self in case the user is set as an allowed user for any institution. + [$inst, $access, $err] = InstitutionHelper::checkSelfInst($request); + if ($err != "") { + return ["", $err]; + } + + return [$inst, ""]; } // Set the institution id for Datakinders, return an error if any. diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php index deb59c2..e842d65 100644 --- a/app/Http/Controllers/ApiController.php +++ b/app/Http/Controllers/ApiController.php @@ -21,75 +21,16 @@ class ApiController extends Controller // $out = new \Symfony\Component\Console\Output\ConsoleOutput(); // $out->writeln("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1"); - // Downloading inference output - public function downloadInfData(Request $request, string $filename) - { - [$inst, $instErr] = InstitutionHelper::GetInstitution($request); - [$tok, $tokErr] = TokenHelper::GetToken($request); - if ($tok == "") { - return response()->json(['error' => $tokErr], 401); - } - if ($inst == "") { - return response()->json(['error' => $instErr], 401); - } - $headers = [ - 'Authorization' => 'Bearer '.$tok, - 'accept' => 'application/json', - 'Cache-Control' => 'no-cache', - ]; - $resp = Http::withHeaders($headers)->get(env('BACKEND_URL').'/institutions/'.$inst.'/download_url/'.$filename); - - if ($resp->getStatusCode() != 200 ) { - $errMsg = json_decode($resp->getBody()); - if ($errMsg == null) { - return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); - } - return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - } - return $resp; - } - - // This returns batch and file info for a given inst. - public function viewUploadedData(Request $request) + // Constructs a query for Datakinder cases that does not retrieve institution info. + public function constructDatakinderRequest(Request $request, string $url_piece, string $method, $post_body) { - [$inst, $instErr] = InstitutionHelper::GetInstitution($request); [$tok, $tokErr] = TokenHelper::GetToken($request); if ($tok == "") { return response()->json(['error' => $tokErr], 401); } - if ($inst == "") { - return response()->json(['error' => $instErr], 401); - } - - $headers = [ - 'Authorization' => 'Bearer '.$tok, - 'accept' => 'application/json', - 'Cache-Control' => 'no-cache', - ]; - - $resp = Http::withHeaders($headers)->get(env('BACKEND_URL').'/institutions/'.$inst.'/input'); - - if ($resp->getStatusCode() != 200 ) { - $errMsg = json_decode($resp->getBody()); - if ($errMsg == null) { - return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); - } - return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - - } - return $resp; - } - // TODO: delete. this is only for debugging - public function viewInputData(Request $request) - { - [$inst, $instErr] = InstitutionHelper::GetInstitution($request); - [$tok, $tokErr] = TokenHelper::GetToken($request); - if ($tok == "") { - return response()->json(['error' => $tokErr], 401); - } - if ($inst == "") { - return response()->json(['error' => $instErr], 401); + if ($request->user()->access_type != "DATAKINDER") { + return response()->json(['error' => 'Only datakinders can perform this action'], 401); } $headers = [ @@ -97,39 +38,19 @@ public function viewInputData(Request $request) 'accept' => 'application/json', 'Cache-Control' => 'no-cache', ]; - - $resp = Http::withHeaders($headers)->get(env('BACKEND_URL').'/institutions/'.$inst.'/input_debugging'); - - if ($resp->getStatusCode() != 200 ) { - $errMsg = json_decode($resp->getBody()); - if ($errMsg == null) { - return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); + $url = env('BACKEND_URL').$url_piece; + $resp = null; + if ($method == "GET") { + $resp = Http::withHeaders($headers)->get($url); + } else if ($method == "POST") { + if ($post_body == null) { + $resp = Http::withHeaders($headers)->post($url); + } else { + $resp = Http::withHeaders($headers)->post($url, $post_body); } - return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - - } - return $resp; - } - - public function fileUploadApi(Request $request, string $filename) - { - - [$inst, $instErr] = InstitutionHelper::GetInstitution($request); - [$tok, $tokErr] = TokenHelper::GetToken($request); - if ($tok == "") { - return response()->json(['error' => $tokErr], 401); + } else { + return response()->json(['error' => 'Unrecognized HTTP method'], 500); } - if ($inst == "") { - return response()->json(['error' => $instErr], 401); - } - - $headers = [ - 'Authorization' => 'Bearer '.$tok, - 'accept' => 'application/json', - 'Cache-Control' => 'no-cache', - ]; - - $resp = Http::withHeaders($headers)->get(env('BACKEND_URL').'/institutions/'.$inst.'/upload_url/'.$filename); if ($resp->getStatusCode() != 200 ) { $errMsg = json_decode($resp->getBody()); @@ -137,62 +58,25 @@ public function fileUploadApi(Request $request, string $filename) return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); } return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - } return $resp; } - public function fileValidateApi(Request $request, string $filename) + public function addDatakinderApi(Request $request) { - - [$inst, $instErr] = InstitutionHelper::GetInstitution($request); - [$tok, $tokErr] = TokenHelper::GetToken($request); - if ($tok == "") { - return response()->json(['error' => $tokErr], 401); - } - if ($inst == "") { - return response()->json(['error' => $instErr], 401); - } - - $headers = [ - 'Authorization' => 'Bearer '.$tok, - 'accept' => 'application/json', - 'Cache-Control' => 'no-cache', - ]; - - $resp = Http::withHeaders($headers)->post(env('BACKEND_URL').'/institutions/'.$inst.'/input/validate/'.$filename); - - if ($resp->getStatusCode() != 200 ) { - $errMsg = json_decode($resp->getBody()); - if ($errMsg == null) { - return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); - } - return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - + $emails_list = $request->input('emails'); + if ( $emails_list == null || sizeof($emails_list) == 0) { + return response()->json(['error' => 'At least one email required.'], 400); } - return $resp; + return ApiController::constructDatakinderRequest($request, '/datakinders', "POST", $emails_list); } public function createInstApi(Request $request) { - [$tok, $tokErr] = TokenHelper::GetToken($request); - if ($tok == "") { - return response()->json(['error' => $tokErr], 401); - } - - if ($request->user()->access_type != "DATAKINDER") { - return response()->json(['error' => 'Only datakinders can create institutions'], 401); - } if ($request->input('name') == null || $request->input('name') == "") { return response()->json(['error' => 'Name required.'], 400); } - - $headers = [ - 'Authorization' => 'Bearer '.$tok, - 'accept' => 'application/json', - 'Cache-Control' => 'no-cache', - ]; $post_request_body = [ 'name' => $request->input('name'), ]; @@ -211,40 +95,39 @@ public function createInstApi(Request $request) if ($request->input('retention_days') != null && $request->input('retention_days') != "") {$post_request_body['retention_days'] = $request->input('retention_days');} - $resp = Http::withHeaders($headers)->post(env('BACKEND_URL').'/institutions', $post_request_body); - - if ($resp->getStatusCode() != 200 ) { - $errMsg = json_decode($resp->getBody()); - if ($errMsg == null) { - return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); - } - return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - } - return $resp; + return ApiController::constructDatakinderRequest($request, '/institutions', "POST", $post_request_body); } - public function addDatakinderApi(Request $request) + // Constructs a query without the BACKEND_URL+/institutions/ prefix. + public function constructInstRequest(Request $request, string $url_piece, string $method, $post_body) { + [$inst, $instErr] = InstitutionHelper::GetInstitution($request); [$tok, $tokErr] = TokenHelper::GetToken($request); if ($tok == "") { return response()->json(['error' => $tokErr], 401); } - - if ($request->user()->access_type != "DATAKINDER") { - return response()->json(['error' => 'Only Datakinders can add other Datakinders'], 401); - } - $emails_list = $request->input('emails'); - if ( $emails_list == null || sizeof($emails_list) == 0) { - return response()->json(['error' => 'At least one email required.'], 400); + if ($inst == "") { + return response()->json(['error' => $instErr], 401); } - $headers = [ 'Authorization' => 'Bearer '.$tok, 'accept' => 'application/json', 'Cache-Control' => 'no-cache', ]; - $resp = Http::withHeaders($headers)->post(env('BACKEND_URL').'/datakinders', $emails_list); + $url = env('BACKEND_URL').'/institutions/'.$inst.$url_piece; + $resp = null; + if ($method == "GET") { + $resp = Http::withHeaders($headers)->get($url); + } else if ($method == "POST") { + if ($post_body == null) { + $resp = Http::withHeaders($headers)->post($url); + } else { + $resp = Http::withHeaders($headers)->post($url, $post_body); + } + } else { + return response()->json(['error' => 'Unrecognized HTTP method'], 500); + } if ($resp->getStatusCode() != 200 ) { $errMsg = json_decode($resp->getBody()); @@ -259,23 +142,8 @@ public function addDatakinderApi(Request $request) public function createBatch(Request $request) { - [$inst, $instErr] = InstitutionHelper::GetInstitution($request); - [$tok, $tokErr] = TokenHelper::GetToken($request); - if ($tok == "") { - return response()->json(['error' => $tokErr], 401); - } - if ($inst == "") { - return response()->json(['error' => $instErr], 401); - } - - $headers = [ - 'Authorization' => 'Bearer '.$tok, - 'accept' => 'application/json', - 'Cache-Control' => 'no-cache', - ]; $post_request_body = [ 'name' => $request->input('name'), - ]; if ($request->input('description') != null && $request->input('description') != "") {$post_request_body['description'] = $request->input('description');} @@ -283,19 +151,49 @@ public function createBatch(Request $request) {$post_request_body['batch_disabled'] = $request->input('batch_disabled');} if ($request->input('file_names') != null) {$post_request_body['file_names'] = $request->input('file_names');} - $resp = Http::withHeaders($headers)->post(env('BACKEND_URL').'/institutions/'.$inst.'/batch', $post_request_body); - if ($resp->getStatusCode() != 200 ) { - $errMsg = json_decode($resp->getBody()); - if ($errMsg == null) { - return response()->json(['error' => 'Error code: '.$resp->getStatusCode()], $resp->getStatusCode()); - } - return response()->json(['error' => $errMsg->detail], $resp->getStatusCode()); - } - return $resp; + return ApiController::constructInstRequest($request, '/batch', "POST", $post_request_body); + } + + + // Retrieves the GCS upload URL. + public function fileUploadApi(Request $request, string $filename) + { + return ApiController::constructInstRequest($request, '/upload_url/'.$filename, "GET", null); + } + + // Validates a file that has been uploaded to the GCS bucket already. + public function fileValidateApi(Request $request, string $filename) + { + return ApiController::constructInstRequest($request, '/input/validate/'.$filename, "POST", null); + } + + // This shows all output data. + public function viewOutputData(Request $request) + { + return ApiController::constructInstRequest($request, '/output', "GET"); + } + + // Downloading inference output + public function downloadInfData(Request $request, string $filename) + { + return ApiController::constructInstRequest($request, '/download_url/'.$filename, "GET", null); + } + + // This returns batch and file info for a given inst. + public function viewUploadedData(Request $request) + { + return ApiController::constructInstRequest($request, '/input', "GET", null); } + // TODO: delete. this is only for debugging + public function viewInputData(Request $request) + { + return ApiController::constructInstRequest($request, '/input_debugging', "GET", null); + } + + public function exampleFunction(Request $request) { $query = http_build_query($request->query()); diff --git a/resources/js/Pages/CreateInst.jsx b/resources/js/Pages/CreateInst.jsx index 1654e00..73362f1 100644 --- a/resources/js/Pages/CreateInst.jsx +++ b/resources/js/Pages/CreateInst.jsx @@ -153,8 +153,57 @@ export default function CreateInst() { name="state" className="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500" > - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/js/Pages/Dashboard.jsx b/resources/js/Pages/Dashboard.jsx index e06ac34..1ab6c62 100644 --- a/resources/js/Pages/Dashboard.jsx +++ b/resources/js/Pages/Dashboard.jsx @@ -15,13 +15,6 @@ export default function Dashboard() { )} > -
- TO TEST THE VALIDATION AND UPLOAD FLOW: please login using username: - tester-frontend@datakind.org and password: "password" with no quotes. - Then, go to 'Admin Actions' > 'Set Institution' and follow the instructions there for the - dev bucket and hit submit -- after that you will be able to upload to - the dev bucket (this particular dev inst is set to PDP type data). -
); } diff --git a/resources/js/Pages/Welcome.jsx b/resources/js/Pages/Welcome.jsx index 47f293a..4036db6 100644 --- a/resources/js/Pages/Welcome.jsx +++ b/resources/js/Pages/Welcome.jsx @@ -10,6 +10,13 @@ export default function Welcome() {
SST WEBAPP FRONT PAGE!
+
+ TO TEST THE VALIDATION AND UPLOAD FLOW: please login using username: + tester-frontend@datakind.org and password: "password" with no quotes. + Then, go to 'Admin Actions' > 'Set Institution' and follow the instructions there for the + dev bucket and hit submit -- after that you will be able to upload to + the dev bucket (this particular dev inst is set to PDP type data). +
diff --git a/routes/web.php b/routes/web.php index 6565049..37b80b8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -57,6 +57,7 @@ function () { Route::middleware('auth')->get('/view-input-data', [ApiController::class, 'viewInputData']); Route::middleware('auth')->get('/view-uploaded-data', [ApiController::class, 'viewUploadedData']); +Route::middleware('auth')->get('/view-output-data', [ApiController::class, 'viewOutputData']); Route::middleware('auth')->get('/run-inference', function () {