Skip to content

Commit 7ec7548

Browse files
authored
Merge pull request #748 from Thoth2023/develop
Develop
2 parents 4bc59d2 + 2d82ada commit 7ec7548

File tree

8 files changed

+271
-33
lines changed

8 files changed

+271
-33
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace App\Jobs;
4+
5+
use App\Models\Project\Conducting\Papers;
6+
use App\Services\SnowballingService;
7+
use Illuminate\Bus\Queueable;
8+
use Illuminate\Contracts\Queue\ShouldQueue;
9+
use Illuminate\Foundation\Bus\Dispatchable;
10+
use Illuminate\Queue\InteractsWithQueue;
11+
use Illuminate\Queue\SerializesModels;
12+
use Illuminate\Support\Facades\Log;
13+
14+
class AtualizarDadosSemantic implements ShouldQueue
15+
{
16+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
17+
18+
protected $paperId;
19+
protected $doi;
20+
protected $title;
21+
22+
public function __construct($paperId, $doi = null, $title = null)
23+
{
24+
$this->paperId = $paperId;
25+
$this->doi = $doi;
26+
$this->title = $title;
27+
Log::info("Job criado para atualização via Semantic Scholar (paper ID: {$this->paperId})");
28+
}
29+
30+
public function handle()
31+
{
32+
Log::info("Iniciando atualização via Semantic Scholar para o paper ID {$this->paperId}");
33+
34+
$service = new SnowballingService();
35+
$query = !empty($this->doi) ? $this->doi : $this->title;
36+
37+
$result = $service->fetch($query);
38+
39+
if (!$result || empty($result['article'])) {
40+
Log::warning("Nenhum dado retornado do Semantic Scholar para o paper ID {$this->paperId}");
41+
return;
42+
}
43+
44+
$article = $result['article'];
45+
$paper = Papers::find($this->paperId);
46+
47+
if (!$paper) {
48+
Log::warning("Paper com ID {$this->paperId} não encontrado no banco de dados.");
49+
return;
50+
}
51+
52+
// Atualizar campos conforme tipo de consulta (via DOI ou via título)
53+
if (empty($this->doi) && !empty($this->title)) {
54+
// Atualização via título → preencher DOI
55+
$paper->doi = $article['doi'] ?? $paper->doi;
56+
} elseif (!empty($this->doi) && empty($this->title)) {
57+
// Atualização via DOI → preencher título
58+
$paper->title = $article['title'] ?? $paper->title;
59+
}
60+
61+
// Atualizar campos comuns
62+
$paper->abstract = $article['abstract'] ?? $paper->abstract;
63+
$paper->keywords = $this->extractKeywords($article);
64+
$paper->author = $article['authors'] ?? $paper->author;
65+
66+
$paper->save();
67+
68+
Log::info("Atualização via Semantic Scholar concluída para o paper ID {$this->paperId}");
69+
}
70+
71+
private function extractKeywords(array $article): string
72+
{
73+
if (!empty($article['keywords'])) {
74+
if (is_array($article['keywords'])) {
75+
return implode(', ', $article['keywords']);
76+
}
77+
return $article['keywords'];
78+
}
79+
80+
// Fallback: tentar inferir palavras-chave a partir do abstract
81+
if (!empty($article['abstract'])) {
82+
$abstract = strtolower($article['abstract']);
83+
$words = array_filter(explode(' ', $abstract), fn($w) => strlen($w) > 6);
84+
$unique = array_slice(array_unique($words), 0, 8);
85+
return implode(', ', $unique);
86+
}
87+
88+
return '';
89+
}
90+
}

app/Livewire/Conducting/StudySelection/ButtonsUpdatePaper.php

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
use App\Jobs\AtualizarDadosCrossref;
66
use App\Jobs\AtualizarDadosSpringer;
7+
use App\Jobs\AtualizarDadosSemantic;
78
use App\Models\Project\Conducting\Papers;
8-
use App\Utils\ToastHelper; // Certifique-se de que o ToastHelper está corretamente importado
9+
use App\Utils\ToastHelper;
910
use Illuminate\Support\Facades\Log;
1011
use Livewire\Attributes\On;
1112
use Livewire\Component;
@@ -22,14 +23,12 @@ public function mount($paperId, $projectId)
2223
{
2324
$this->projectId = $projectId;
2425
$this->paperId = $paperId;
25-
2626
$this->refreshData();
2727
}
2828

2929
#[On('refresh-paper-data')]
3030
public function refreshData()
3131
{
32-
// Recarrega as informações do paper
3332
$paper = Papers::find($this->paperId);
3433
if ($paper) {
3534
$this->abstract = $paper->abstract;
@@ -42,40 +41,48 @@ public function refreshData()
4241
public function atualizarDadosFaltantes()
4342
{
4443
if (empty($this->doi) && empty($this->title)) {
45-
// Usar ToastHelper para exibir mensagem de erro
46-
$this->toast('DOI ou título do paper necessário para buscar dados.', 'error');
44+
$this->toast(__('project/conducting.study-selection.modal.buttons.crossref.error_missing_data'), 'error');
4745
$this->dispatch('refresh-paper-data');
4846
return;
4947
}
5048

5149
Log::info("Despachando Job para paper ID {$this->paperId}, DOI: {$this->doi} e Título: {$this->title}");
52-
5350
AtualizarDadosCrossref::dispatch($this->paperId, $this->doi, $this->title);
5451

55-
// Usar ToastHelper para exibir mensagem de sucesso
56-
$this->toast('A atualização dos dados foi solicitada via CrossRef, verifique se os dados foram atualizados.', 'success');
52+
$this->toast(__('project/conducting.study-selection.modal.buttons.crossref.success'), 'success');
5753
$this->dispatch('refresh-paper-data');
5854
}
5955

6056
public function atualizarDadosSpringer()
6157
{
6258
if (empty($this->doi)) {
63-
// Usar ToastHelper para exibir mensagem de erro
64-
$this->toast('DOI necessário para buscar dados via Springer.', 'error');
59+
$this->toast(__('project/conducting.study-selection.modal.buttons.springer.error_missing_doi'), 'error');
6560
$this->dispatch('refresh-paper-data');
6661
return;
6762
}
6863

6964
Log::info("Despachando Job para atualização via Springer para paper ID {$this->paperId}");
70-
7165
AtualizarDadosSpringer::dispatch($this->paperId, $this->doi);
7266

73-
// Usar ToastHelper para exibir mensagem de sucesso
74-
$this->toast('A atualização dos dados foi solicitada via Springer, verifique se os dados foram atualizados.', 'success');
67+
$this->toast(__('project/conducting.study-selection.modal.buttons.springer.success'), 'success');
68+
$this->dispatch('refresh-paper-data');
69+
}
70+
71+
public function atualizarDadosSemantic()
72+
{
73+
if (empty($this->doi) && empty($this->title)) {
74+
$this->toast(__('project/conducting.study-selection.modal.buttons.semantic.error_missing_query'), 'error');
75+
$this->dispatch('refresh-paper-data');
76+
return;
77+
}
78+
79+
Log::info("Despachando Job para atualização via Semantic Scholar para paper ID {$this->paperId}");
80+
AtualizarDadosSemantic::dispatch($this->paperId, $this->doi, $this->title);
81+
82+
$this->toast(__('project/conducting.study-selection.modal.buttons.semantic.success'), 'success');
7583
$this->dispatch('refresh-paper-data');
7684
}
7785

78-
// Função auxiliar para enviar mensagens de toast
7986
private function toast(string $message, string $type)
8087
{
8188
$this->dispatch('buttons-update-paper', ToastHelper::dispatch($type, $message));
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace App\Livewire\Conducting\StudySelection;
4+
5+
use App\Models\Project;
6+
use App\Models\Project\Conducting\Papers;
7+
use Livewire\Attributes\On;
8+
use Livewire\Component;
9+
10+
class PaperDoiUrl extends Component
11+
{
12+
public $paperId;
13+
public $projectId;
14+
public $doi;
15+
public $url;
16+
17+
public function mount($paperId, $projectId)
18+
{
19+
$this->projectId = $projectId;
20+
$this->paperId = $paperId;
21+
$this->loadPaperData();
22+
}
23+
24+
#[On('refresh-paper-data')]
25+
public function loadPaperData()
26+
{
27+
$paper = Papers::find($this->paperId);
28+
29+
if ($paper) {
30+
$this->doi = $paper->doi;
31+
$this->url = $paper->url;
32+
33+
// Caso a URL esteja vazia, preencher com o link completo do DOI (se existir)
34+
if (empty($this->url) && !empty($this->doi)) {
35+
$this->url = $this->buildDoiUrl($this->doi);
36+
}
37+
}
38+
}
39+
40+
private function buildDoiUrl(?string $doi): ?string
41+
{
42+
if (empty($doi)) {
43+
return null;
44+
}
45+
46+
// Se já contiver "doi.org", retorna como está
47+
if (str_contains($doi, 'doi.org')) {
48+
return $doi;
49+
}
50+
51+
// Se já for um link completo (http/https), retorna direto
52+
if (preg_match('/^https?:\/\//', $doi)) {
53+
return $doi;
54+
}
55+
56+
// Caso contrário, monta o link padrão
57+
return "https://doi.org/" . ltrim($doi, '/');
58+
}
59+
60+
public function render()
61+
{
62+
return view('livewire.conducting.study-selection.paper-doi-url');
63+
}
64+
}

lang/en/project/conducting.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,21 @@
112112
'unclassified' => 'Unclassified',
113113
'final-decision' => 'Final Decision Group about paper?',
114114
],
115+
'buttons' => [
116+
'crossref' => [
117+
'error_missing_data' => 'DOI or paper title is required to fetch data via CrossRef.',
118+
'success' => 'Data update requested via CrossRef. Please verify if the information has been updated.',
119+
],
120+
'springer' => [
121+
'error_missing_doi' => 'DOI is required to fetch data via Springer.',
122+
'success' => 'Data update requested via Springer. Please verify if the information has been updated.',
123+
],
124+
'semantic' => [
125+
'error_missing_query' => 'DOI or title is required to fetch data via Semantic Scholar.',
126+
'success' => 'Data update requested via Semantic Scholar. Please verify if the information has been updated.',
127+
],
128+
],
129+
'update_via' => 'Update via:',
115130
'save' => 'Save',
116131
'update' => 'Update',
117132
'confirm' => 'Confirm',
@@ -481,12 +496,12 @@
481496
<li>To add researchers, navigate to <b>"My Projects->Team"</b></li>
482497
</ul>
483498
<br>
484-
<b>CSV Format Guidelines:</b><br>
499+
<b>CSV Format Guidelines (Springer Link):</b><br>
485500
Your CSV file must include the following column headers:<br>
486501
<ul>
487502
<li>"<b>Item Title</b>" – used as the paper title</li>
488503
<li>"<b>Authors</b>" – list of authors</li>
489-
<li>"<b>Item DOI</b>" – Digital Object Identifier</li>
504+
<li>"Item DOI" – Digital Object Identifier</li>
490505
<li>"URL" – link to the paper</li>
491506
<li>"Publication Year" – publication year</li>
492507
<li>"Book Series Title" – optional book series name</li>

lang/pt_BR/project/conducting.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,21 @@
111111
'unclassified' => 'Unclassified',
112112
'final-decision' => 'Decisão final do grupo sobre o paper?',
113113
],
114+
'buttons' => [
115+
'crossref' => [
116+
'error_missing_data' => 'É necessário informar o DOI ou o título do paper para buscar dados via CrossRef.',
117+
'success' => 'A atualização dos dados foi solicitada via CrossRef. Verifique se as informações foram atualizadas.',
118+
],
119+
'springer' => [
120+
'error_missing_doi' => 'É necessário informar o DOI para buscar dados via Springer.',
121+
'success' => 'A atualização dos dados foi solicitada via Springer. Verifique se as informações foram atualizadas.',
122+
],
123+
'semantic' => [
124+
'error_missing_query' => 'É necessário informar o DOI ou o título para buscar dados via Semantic Scholar.',
125+
'success' => 'A atualização dos dados foi solicitada via Semantic Scholar. Verifique se as informações foram atualizadas.',
126+
],
127+
],
128+
'update_via' => 'Atualizar via:',
114129
'save' => 'Salvar',
115130
'update' => 'Atualizar',
116131
'confirm' => 'Confirmar',
@@ -302,12 +317,12 @@
302317
<li>Para adicionar pesquisadores, navegue até <b>"Meus Projetos->Colaboradores"</b></li>
303318
</ul>
304319
<br>
305-
<b>Orientações para o formato CSV:</b><br>
320+
<b>Orientações para o formato CSV (Springer Link):</b><br>
306321
O arquivo CSV deve conter os seguintes cabeçalhos de coluna:<br>
307322
<ul>
308323
<li>"<b>Item Title</b>" – usado como o título do estudo</li>
309324
<li>"<b>Authors</b>" – lista de autores</li>
310-
<li>"<b>Item DOI</b>" – identificador digital do objeto</li>
325+
<li>"Item DOI" – identificador digital do objeto</li>
311326
<li>"URL" – link opcional para o estudo</li>
312327
<li>"Publication Year" – ano de publicação</li>
313328
<li>"Book Series Title" – nome da série de livros</li>

resources/views/livewire/conducting/study-selection/buttons-update-paper.blade.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
<div>
2+
<p>{{ __('project/conducting.study-selection.modal.update_via') }}</p>
3+
@if(empty($abstract) || empty($keywords) || empty($doi) || empty($title))
4+
<a class="btn py-1 px-3 btn-outline-primary" data-toggle="tooltip" data-original-title="Atualizar Dados Via Semantic Scholar" wire:click="atualizarDadosSemantic">
5+
<i class="fa-solid fa-refresh"></i>
6+
Semantic Scholar
7+
</a>
8+
@endif
29
@if(empty($abstract) || empty($keywords))
310
<a class="btn py-1 px-3 btn-outline-primary" data-toggle="tooltip" data-original-title="Atualizar Dados Via CrossRef" wire:click="atualizarDadosFaltantes">
411
<i class="fa-solid fa-refresh"></i>
5-
Via CrossRef
12+
CrossRef
613
</a>
714
<a class="btn py-1 px-3 btn-outline-primary" data-toggle="tooltip" data-original-title="Atualizar Dados Via Springer" wire:click="atualizarDadosSpringer">
815
<i class="fa-solid fa-refresh"></i>
9-
Via SpringerLink
16+
SpringerLink
1017
</a>
1118
@endif
19+
1220
<div wire:ignore.self class="modal fade" id="successModalUpdate" tabindex="-1" role="dialog" aria-labelledby="successModalLabel" aria-hidden="true">
1321
<div class="modal-dialog modal-dialog-centered" role="document">
1422
<div class="modal-content">
1523
<div class="modal-header">
16-
<h5 class="modal-title" id="successModalLabel">Success</h5>
24+
<h5 class="modal-title" id="successModalLabel">{{ __('project/conducting.study-selection.modal.success') }}</h5>
1725
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
1826
</div>
1927
<div class="modal-body">
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<div>
2+
3+
{{-- Botão DOI --}}
4+
@if(!empty($doi))
5+
@php
6+
// Se o DOI já contiver "http", usar direto. Caso contrário, montar o link completo
7+
$doiLink = str_contains($doi, 'http') ? $doi : 'https://doi.org/' . ltrim($doi);
8+
@endphp
9+
10+
<a class="btn py-1 px-3 btn-outline-dark"
11+
data-toggle="tooltip"
12+
data-original-title="DOI"
13+
href="{{ $doiLink }}"
14+
target="_blank">
15+
<i class="fa-solid fa-arrow-up-right-from-square"></i>
16+
DOI
17+
</a>
18+
@endif
19+
20+
{{-- Botão URL --}}
21+
@php
22+
// Se a URL estiver vazia, usar o link do DOI (se existir)
23+
$urlLink = !empty($url)
24+
? $url
25+
: (!empty($doi) ? (str_contains($doi, 'http') ? $doi : 'https://doi.org/' . ltrim($doi)) : null);
26+
@endphp
27+
28+
@if(!empty($urlLink))
29+
<a class="btn py-1 px-3 btn-outline-success"
30+
data-toggle="tooltip"
31+
data-original-title="URL"
32+
href="{{ $urlLink }}"
33+
target="_blank">
34+
<i class="fa-solid fa-link"></i>
35+
URL
36+
</a>
37+
@endif
38+
39+
</div>
40+
41+
@script
42+
<script>
43+
$wire.on('paper-doi-url', ([{ message, type }]) => {
44+
toasty({ message, type });
45+
});
46+
</script>
47+
@endscript

0 commit comments

Comments
 (0)