Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions app/Actions/Project/PublishEmbargoProject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace App\Actions\Project;

use App\Jobs\ProcessSubmission;
use App\Models\Project;
use Carbon\Carbon;

class PublishEmbargoProject
{
/**
* Publish the given embargo project.
*
* @throws \InvalidArgumentException
*/
public function publish(Project $project): array
{
// Verify this is an embargo project
if ($project->status !== 'embargo') {
throw new \InvalidArgumentException('Project is not in embargo status.');
}

// Check if project already has DOI (it should for embargo projects)
if (! $project->identifier) {
throw new \InvalidArgumentException('Project missing DOI. Cannot publish embargo project without identifier.');
}

// Update project status and release date to current time
$project->status = 'queued';
$project->release_date = Carbon::now();
$project->save();

// Dispatch the processing job
ProcessSubmission::dispatch($project);

return [
'project' => $project->fresh(),
'message' => 'Embargo project successfully queued for publication.',
];
}
}
94 changes: 94 additions & 0 deletions app/Actions/Project/SetEmbargoProject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace App\Actions\Project;

use App\Models\Project;
use App\Models\Validation;
use Carbon\Carbon;

class SetEmbargoProject
{
/**
* Set the given project to embargo status with a future release date.
*
* @throws \InvalidArgumentException
*/
public function setEmbargo(Project $project, string $releaseDate): array
{
// Check if release date is in the future (embargo)
$releaseDateTime = Carbon::parse($releaseDate);
if (! $releaseDateTime->isFuture()) {
throw new \InvalidArgumentException('Release date must be in the future for embargo projects.');
}

// Set project release date and status
$project->release_date = $releaseDate;
$project->status = 'embargo';
$project->save();

// Validate the project first
$validation = $project->validation;
if (! $validation) {
$validation = new Validation;
$validation->save();
$project->validation()->associate($validation);
$project->save();
}

$validation->process();
$validation = $validation->fresh();

if (! $validation['report']['project']['status']) {
$exception = new \InvalidArgumentException('Validation failing. Please provide all the required data and try again. If the problem persists, please contact us.');
$exception->validation = $validation;
throw $exception;
}

// Generate DOI based on project_enabled status
$draft = $project->draft;
$assigner = app(AssignIdentifier::class);

if ($draft && $draft->project_enabled) {
// Generate DOI for project
$assigner->assign($project->fresh());
} else {
// Generate DOI for studies
$studies = $project->studies;
if ($studies->isNotEmpty()) {
// Copy license to studies and datasets first
foreach ($studies as $study) {
$study->license_id = $project->license_id;
$study->save();
foreach ($study->datasets as $dataset) {
$dataset->license_id = $project->license_id;
$dataset->save();
}
}

// Check individual study validation
$allStudiesValid = true;
foreach ($validation['report']['project']['studies'] as $study) {
if (! $study['status']) {
$allStudiesValid = false;
break;
}
}

if (! $allStudiesValid) {
$exception = new \InvalidArgumentException('Study validation failing. Please provide all the required data and try again. If the problem persists, please contact us.');
$exception->validation = $validation;
throw $exception;
}

// Generate DOI for studies
$assigner->assign($studies);
}
}

return [
'project' => $project->fresh(),
'validation' => $validation,
'message' => 'Project set for embargo release on '.$releaseDateTime->format('Y-m-d'),
];
}
}
157 changes: 157 additions & 0 deletions app/Console/Commands/PublishEmbargoProjects.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

namespace App\Console\Commands;

use App\Actions\Project\PublishEmbargoProject;
use App\Models\EmbargoReminder;
use App\Models\Project;
use App\Notifications\EmbargoReleaseReminderNotification;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;

class PublishEmbargoProjects extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'nmrxiv:publish-embargo-projects';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Send embargo release reminders and publish embargoed projects if the release date is reached';

/**
* Execute the console command.
*/
public function handle(PublishEmbargoProject $embargoPublisher): int
{
return DB::transaction(function () use ($embargoPublisher) {
$now = Carbon::now();
$remindersSent = 0;
$publishedCount = 0;

// Send 1 week reminders
$this->sendReminders($now->copy()->addDays(7), 7, 'week', $remindersSent);

// Send 3 days reminders
$this->sendReminders($now->copy()->addDays(3), 3, 'days', $remindersSent);

// Send 1 day reminders
$this->sendReminders($now->copy()->addDays(1), 1, 'day', $remindersSent);

// Publish projects that have reached their release date
$publishedCount = $this->publishReadyProjects($embargoPublisher, $now);

// Clean up old reminder records for published projects
$this->cleanupOldReminders();

$this->info("Sent {$remindersSent} embargo release reminders.");
$this->info("Published {$publishedCount} embargo projects.");

return 0;
});
}

/**
* Send reminder notifications for projects approaching release date
*/
private function sendReminders(Carbon $targetDate, int $daysUntilRelease, string $reminderType, int &$remindersSent): void
{
$projects = Project::where([
['status', 'embargo'],
['is_public', false],
['is_archived', false],
])->whereNotNull('release_date')
->whereNotNull('identifier')
->whereDate('release_date', $targetDate->toDateString())
->whereDoesntHave('embargoReminders', function ($query) use ($daysUntilRelease) {
$query->where('days_before_release', $daysUntilRelease);
})
->with('owner')
->get();

foreach ($projects as $project) {
try {
$this->info("Sending {$daysUntilRelease} day reminder for project: {$project->name} (ID: {$project->id})");

// Send reminder notification
Notification::send($project->owner, new EmbargoReleaseReminderNotification($project, $daysUntilRelease));

// Record that reminder was sent
EmbargoReminder::create([
'project_id' => $project->id,
'days_before_release' => $daysUntilRelease,
'sent_at' => Carbon::now(),
]);

$remindersSent++;
$this->info("Successfully sent {$daysUntilRelease} day reminder for: {$project->name}");

} catch (\Exception $e) {
$this->error("Failed to send reminder for project {$project->name}: {$e->getMessage()}");
}
}
}

/**
* Publish projects that have reached their release date
*/
private function publishReadyProjects(PublishEmbargoProject $embargoPublisher, Carbon $now): int
{
$this->info("Looking for projects to publish with release_date <= {$now->toDateString()}");

$projects = Project::where([
['status', 'embargo'],
['is_public', false],
['is_archived', false],
])->whereNotNull('release_date')
->whereNotNull('identifier')
->whereDate('release_date', '<=', $now->toDateString())
->get();

$this->info("Found {$projects->count()} projects eligible for publishing");

$publishedCount = 0;

foreach ($projects as $project) {
try {
$this->info("Publishing embargo project: {$project->name} (ID: {$project->id})");

$result = $embargoPublisher->publish($project);

$publishedCount++;
$this->info("Successfully queued project for publication: {$project->name}");

} catch (\InvalidArgumentException $e) {
$this->error("Failed to publish project {$project->name}: {$e->getMessage()}");
} catch (\Exception $e) {
$this->error("Unexpected error publishing project {$project->name}: {$e->getMessage()}");
}
}

return $publishedCount;
}

/**
* Clean up old embargo reminder records for projects that are no longer embargoed
*/
private function cleanupOldReminders(): void
{
$deletedCount = EmbargoReminder::whereHas('project', function ($query) {
$query->where('status', '!=', 'embargo')
->orWhere('is_public', true)
->orWhere('is_archived', true);
})->delete();

if ($deletedCount > 0) {
$this->info("Cleaned up {$deletedCount} old embargo reminder records.");
}
}
}
59 changes: 0 additions & 59 deletions app/Console/Commands/PublishReleasedProjects.php

This file was deleted.

Loading
Loading