Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Orcid integration employment - ready for prod progress #784

Merged
merged 14 commits into from
Oct 18, 2024
1,518 changes: 22 additions & 1,496 deletions .phpstorm.meta.php

Large diffs are not rendered by default.

144 changes: 72 additions & 72 deletions _ide_helper.php

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions app/Actions/CreatePublicationFromManuscript.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,29 @@ public static function handle(ManuscriptRecord $manuscriptRecord, Journal $journ
// create a new publication record
return DB::transaction(function () use ($manuscriptRecord, $journal) {
$publication = $manuscriptRecord->publication()->create([
'title' => $manuscriptRecord->title,
'journal_id' => $journal->id,
'status' => PublicationStatus::ACCEPTED,
'accepted_on' => $manuscriptRecord->accepted_on,
'user_id' => $manuscriptRecord->user_id,
'title' => $manuscriptRecord->title,
'journal_id' => $journal->id,
'status' => PublicationStatus::ACCEPTED,
'accepted_on' => $manuscriptRecord->accepted_on,
'user_id' => $manuscriptRecord->user_id,
]);

// attach the manuscript's authors to the publication
$manuscriptRecord->manuscriptAuthors()->each(function ($manuscriptAuthor) use ($publication) {
$publication->publicationAuthors()->create([
'author_id' => $manuscriptAuthor->author_id,
'organization_id' => $manuscriptAuthor->organization_id,
'is_corresponding_author' => $manuscriptAuthor->is_corresponding_author,
]);
$publication->publicationAuthors()->create([
'author_id' => $manuscriptAuthor->author_id,
'organization_id' => $manuscriptAuthor->organization_id,
'is_corresponding_author' => $manuscriptAuthor->is_corresponding_author,
]);
});

// attach the manuscript's fundingSources to the publication
$manuscriptRecord->fundingSources()->each(function ($fundingSource) use ($publication) {
$publication->fundingSources()->create([
'funder_id' => $fundingSource->funder_id,
'title' => $fundingSource->title,
'description' => $fundingSource->description,
]);
$publication->fundingSources()->create([
'funder_id' => $fundingSource->funder_id,
'title' => $fundingSource->title,
'description' => $fundingSource->description,
]);
});

return $publication;
Expand Down
16 changes: 8 additions & 8 deletions app/Actions/ROR/DownloadLatestRORData.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ public static function handle(?callable $progressCallable = null): ?array
}

$fileName = $fileName = Str::of($url)
->beforeLast("/")
->afterLast("/")
->beforeLast('/')
->afterLast('/')
->toString();
$zipFile = $base_path . '/' . $fileName;
$zipFile = $base_path.'/'.$fileName;

// does the file already exist?
if (! file_exists($zipFile)) {
Expand All @@ -50,11 +50,11 @@ public static function handle(?callable $progressCallable = null): ?array
$update = is_callable($progressCallable);

if ($update) {
$progressCallable('Staring ROR download: ' . $command . '...' . PHP_EOL);
$progressCallable('Staring ROR download: '.$command.'...'.PHP_EOL);
}
$process = Process::timeout(120)->start($command, function ($type, $buffer) use ($progressCallable) {
if ($type === 'stderr') {
$progressCallable('ERROR: ' . $buffer);
$progressCallable('ERROR: '.$buffer);
} else {
$progressCallable($buffer);
}
Expand All @@ -64,12 +64,12 @@ public static function handle(?callable $progressCallable = null): ?array
return null;
}
if ($update) {
$progressCallable('Finished download: ' . $zipFile . PHP_EOL);
$progressCallable('Finished download: '.$zipFile.PHP_EOL);
}
}

// is Json file already extracted?
$jsonFile = $base_path . '/' . Str::beforeLast($fileName, '.') . '_schema_v2.json';
$jsonFile = $base_path.'/'.Str::beforeLast($fileName, '.').'_schema_v2.json';

if (file_exists($jsonFile)) {
return [
Expand All @@ -82,7 +82,7 @@ public static function handle(?callable $progressCallable = null): ?array

$result = Process::path($base_path)->start($command, function ($type, $buffer) use ($progressCallable) {
if ($type === 'stderr') {
$progressCallable('ERROR: ' . $buffer);
$progressCallable('ERROR: '.$buffer);
} else {
$progressCallable($buffer);
}
Expand Down
17 changes: 7 additions & 10 deletions app/Actions/ROR/SyncRORData.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static function handle(string $jsonFilePath, string $version, ?callable $
'FR',
'DE',
'DK',
'NO'
'NO',
]);

$update = is_callable($progressCallback);
Expand Down Expand Up @@ -72,7 +72,7 @@ private static function updateOrCreateOrganization(array $record, string $versio
}

// get default name - ror_display
$ror_display_name = collect($record['names'])->filter( function ($name) {
$ror_display_name = collect($record['names'])->filter(function ($name) {
return in_array('ror_display', $name['types']);
})->first()['value'] ?? null;

Expand All @@ -82,36 +82,33 @@ private static function updateOrCreateOrganization(array $record, string $versio
}

// get english and french names
$name_en = collect($record['names'])->filter( function ($name) {
$name_en = collect($record['names'])->filter(function ($name) {
return in_array('label', $name['types']) && $name['lang'] === 'en';
})->first()['value'] ?? $ror_display_name;

$name_fr = collect($record['names'])->filter( function ($name) {
$name_fr = collect($record['names'])->filter(function ($name) {
return in_array('label', $name['types']) && $name['lang'] === 'fr';
})->first()['value'] ?? $ror_display_name;


// acronyms - ROR 2.0 datasets doens't have lang well implemeted on acronyms yet. Assume EN first.
$acronyms = collect($record['names'])->filter( function ($name) {
$acronyms = collect($record['names'])->filter(function ($name) {
return in_array('acronym', $name['types']);
})->pluck('value')->toArray();

// try to get english and french acronyms
$abbr_en = collect($record['names'])->filter( function ($name) {
$abbr_en = collect($record['names'])->filter(function ($name) {
return in_array('acronym', $name['types']) && $name['lang'] === 'en';
})->first()['value'] ?? $acronyms[0] ?? null;

$abbr_fr = collect($record['names'])->filter( function ($name) {
$abbr_fr = collect($record['names'])->filter(function ($name) {
return in_array('acronym', $name['types']) && $name['lang'] === 'fr';
})->first()['value'] ?? $acronyms[1] ?? $abbr_en;


// bundle up name data for json column
$ror_names = collect($record['names'])->toJson();

$country_code = $record['locations'][0]['geonames_details']['country_code'] ?? null;


// find or create the organization
$organization = Organization::updateOrCreate(
['ror_identifier' => $ror_identifier],
Expand Down
2 changes: 1 addition & 1 deletion app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected function schedule(Schedule $schedule)
*/
protected function commands()
{
$this->load(__DIR__ . '/Commands');
$this->load(__DIR__.'/Commands');

require base_path('routes/console.php');
}
Expand Down
1 change: 0 additions & 1 deletion app/Http/Controllers/Auth/PasswordResetLinkController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException;

class PasswordResetLinkController extends Controller
{
Expand Down
95 changes: 95 additions & 0 deletions app/Http/Controllers/AuthorEmploymentController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace App\Http\Controllers;

use App\Http\Resources\AuthorEmploymentResource;
use App\Models\Author;
use App\Models\AuthorEmployment;
use App\Models\Organization;
use Illuminate\Http\Request;

class AuthorEmploymentController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Author $author)
{
//validate user can do this
$this->authorize('viewAny', [AuthorEmployment::class, $author]);

return AuthorEmploymentResource::collection($author->employments);
}

/**
* Store a newly created resource in storage.
*/
public function store(Author $author, Request $request)
{
$this->authorize('create', [AuthorEmployment::class, $author]);

$defaultOrganization = Organization::getDefaultOrganization();

$validated = $request->validate([
'organization_id' => 'nullable|exists:organizations,id',
'role_title' => 'nullable|string|max:50',
'department_name' => 'nullable|string|max:50',
'start_date' => 'required|date',
'end_date' => 'nullable|date',
]);

// if orgnaiztion isn't the default, it is forbidden
if ($validated['organization_id'] && $validated['organization_id'] !== $defaultOrganization->id) {
abort(403, 'You are not allowed to create employments for other organizations');
}

$authorEmployment = AuthorEmployment::create([
'author_id' => $author->id,
'organization_id' => $defaultOrganization->id,
'role_title' => $validated['role_title'],
'department_name' => $validated['department_name'],
'start_date' => $validated['start_date'],
'end_date' => $validated['end_date'],
]);

return AuthorEmploymentResource::make($authorEmployment);

}

/**
* Display the specified resource.
*/
public function show(Author $author, AuthorEmployment $authorEmployment)
{
$this->authorize('view', $authorEmployment);

return AuthorEmploymentResource::make($authorEmployment);
}

/**
* Update the specified resource in storage.
*/
public function update(Author $author, Request $request, AuthorEmployment $authorEmployment)
{
$this->authorize('update', $authorEmployment);

$validated = $request->validate([
'role_title' => 'nullable|string|max:50',
'department_name' => 'nullable|string|max:50',
'start_date' => 'required|date',
'end_date' => 'nullable|date',
]);

$authorEmployment->update($validated);

return AuthorEmploymentResource::make($authorEmployment->fresh());
}

/**
* Remove the specified resource from storage.
*/
public function destroy(Author $author, AuthorEmployment $authorEmployment)
{
//
}
}
2 changes: 1 addition & 1 deletion app/Http/Controllers/Orcid/FullFlowController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Http\Controllers\Orcid;

use App\Enums\ORCID\ORCIDAuthScope;
use App\Http\Integrations\Orcid\Enums\ORCIDAuthScope;
use App\Models\User;
use App\Traits\LocaleTrait;
use Auth;
Expand Down
8 changes: 4 additions & 4 deletions app/Http/Controllers/Orcid/RevokeTokenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ class RevokeTokenController
public function __invoke()
{
$author = Auth::user()->author;
Log::info('Revoking ORCID token for author ' . $author->id);
Log::info('Revoking ORCID token for author '.$author->id);

// Does author have an ORCID token?
if (! $author->orcid_access_token) {
Log::info('Author ' . $author->id . ' does not have an ORCID token');
Log::info('Author '.$author->id.' does not have an ORCID token');

throw ValidationException::withMessages([
'author' => 'Author does not have an ORCID token',
Expand All @@ -35,7 +35,7 @@ public function __invoke()
$response = Http::asForm()->accept('application/json')->post("https://$baseUrl/oauth/revoke", $payload);

if ($response->status() !== 200) {
Log::error('Failed to revoke ORCID token for author ' . $author->id);
Log::error('Failed to revoke ORCID token for author '.$author->id);
Log::error($response->json());

throw ValidationException::withMessages([
Expand All @@ -45,7 +45,7 @@ public function __invoke()

$author->clearOrcidToken();

Log::info('ORCID token revoked for author ' . $author->id);
Log::info('ORCID token revoked for author '.$author->id);

return response()->json([
'message' => 'ORCID token revoked',
Expand Down
14 changes: 14 additions & 0 deletions app/Http/Integrations/Orcid/Data/AddressData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\Http\Integrations\Orcid\Data;

use Spatie\LaravelData\Data;

class AddressData extends Data
{
public function __construct(
public string $country,
public ?string $region = null,
public string $city = 'Ottawa',
) {}
}
35 changes: 35 additions & 0 deletions app/Http/Integrations/Orcid/Data/DateData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Http\Integrations\Orcid\Data;

use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Data;

class DateData extends Data
{
public function __construct(
#[MapInputName('year.value')]
public ?string $year,

#[MapInputName('month.value')]
public ?string $month,

#[MapInputName('day.value')]
public ?string $day
) {}

/**
* @param string $date Example: 2021-01-01
* @return static
*/
public static function fromString(string $date): self
{
$dateParts = explode('-', $date);

return new self(
year: $dateParts[0] ?? null,
month: $dateParts[1] ?? null,
day: $dateParts[2] ?? null
);
}
}
16 changes: 16 additions & 0 deletions app/Http/Integrations/Orcid/Data/DisambiguatedOrganizationData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Http\Integrations\Orcid\Data;

use Spatie\LaravelData\Attributes\MapName;
use Spatie\LaravelData\Data;

class DisambiguatedOrganizationData extends Data
{
public function __construct(
#[MapName('disambiguated-organization-identifier')]
public string $disambiguatedOrganizationIdentifier,
#[MapName('disambiguation-source')]
public string $disambiguationSource = 'ROR'
) {}
}
Loading
Loading