Skip to content

Commit

Permalink
Merge branch 'dev' into alain_translations
Browse files Browse the repository at this point in the history
# Conflicts:
#	composer.lock
#	resources/views/dashboard.blade.php
  • Loading branch information
alainvd committed May 27, 2024
2 parents 4bb9369 + 9842f84 commit 50c3612
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 3 deletions.
48 changes: 48 additions & 0 deletions app/Console/Commands/StatementsPreprodSyncDateSeq.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Console\Commands;

use App\Jobs\StatementIndexRange;
use App\Jobs\StatementPreprodSyncChunk;
use App\Jobs\StatementSearchableChunk;
use App\Services\DayArchiveService;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;

class StatementsPreprodSyncDateSeq extends Command
{
use CommandTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'statements:preprod-sync-date-seq {date=yesterday} {chunk=500}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Sync statements for a day to the preprod DB';

/**
* Execute the console command.
*/
public function handle(DayArchiveService $day_archive_service): void
{
$chunk = $this->intifyArgument('chunk');
$date = $this->sanitizeDateArgument();

$min = $day_archive_service->getFirstIdOfDate($date);
$max = $day_archive_service->getLastIdOfDate($date);

if ($min && $max) {
Log::info('Syncing started for date: ' . $date->format('Y-m-d') . ' at ' . Carbon::now()->format('Y-m-d H:i:s'));
StatementPreprodSyncChunk::dispatch($min, $max, $chunk);
} else {
Log::warning('Not able to obtain the highest or lowest ID for the day: ' . $date->format('Y-m-d'));
}
}
}
3 changes: 3 additions & 0 deletions app/Http/Controllers/Traits/Sanitizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
trait Sanitizer
{
/**
* @param array $validated
*
* @return array
*/
public function sanitizeData(array $validated): array
Expand All @@ -19,6 +21,7 @@ public function sanitizeData(array $validated): array
$validated['end_date_service_restriction'] = $this->sanitizeDate($validated['end_date_service_restriction'] ?? null);

$validated['territorial_scope'] = $this->european_countries_service->filterSortEuropeanCountries($validated['territorial_scope'] ?? []);

$validated['content_type'] = array_unique($validated['content_type']);
sort($validated['content_type']);
if (array_key_exists('decision_visibility', $validated)) {
Expand Down
67 changes: 67 additions & 0 deletions app/Jobs/StatementPreprodSyncChunk.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace App\Jobs;

use App\Models\Statement;
use App\Services\StatementSearchService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use JsonException;

class StatementPreprodSyncChunk implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Create a new job instance.
*/
public function __construct(public int $min, public int $max, public int $chunk)
{
}

/**
* Execute the job.
* @throws JsonException
*/
public function handle(StatementSearchService $statement_search_service): void
{
// Set this in cache, to emergency stop reindexing.
$stop = Cache::get('stop_reindexing', false);
if (!$stop) {
$end = $this->min + $this->chunk;

if ($end > $this->max) {
$end = $this->max;
}


// Dispatch the next one
if ($end < $this->max) {
$next_min = $this->min + $this->chunk + 1;
// Start the next one.
self::dispatch($next_min, $this->max, $this->chunk);
}

$range = range($this->min, $end);
// Bulk sync

$to_insert = DB::connection('mysql::read')->table('statements')->whereIn('id', $range)->get()->map(function ($item){
return get_object_vars($item);
})->toArray();
Statement::on('mysqlpreprod')->insert($to_insert);

if ($end >= $this->max) {
Log::info('StatementPreprodSyncChunk Max Reached at ' . Carbon::now()->format('Y-m-d H:i:s'));
}
}
}
}
52 changes: 51 additions & 1 deletion app/Models/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ public function toSearchableArray(): array
'decision_visibility' => $this->decision_visibility,
'decision_visibility_single' => implode("__", $this->decision_visibility),
'category_specification' => $this->category_specification,
'decision_visibility_other' => $this->decision_visibilit_other,
'decision_visibility_other' => $this->decision_visibility_other,
'decision_monetary' => $this->decision_monetary,
'decision_monetary_other' => $this->decision_monetary_other,
'decision_provision' => $this->decision_provision,
Expand Down Expand Up @@ -609,6 +609,56 @@ public function toSearchableArray(): array
];
}

public function toSyncableArray(): array
{

return [
'id' => $this->getRawOriginal('id'),
'uuid' => $this->getRawOriginal('uuid'),
'decision_visibility' => $this->getRawOriginal('decision_visibility'),
'decision_visibility_other' => $this->getRawOriginal('decision_visibility_other'),
'decision_monetary' => $this->getRawOriginal('decision_monetary'),
'decision_monetary_other' => $this->getRawOriginal('decision_monetary_other'),
'decision_provision' => $this->getRawOriginal('decision_provision'),
'decision_account' => $this->getRawOriginal('decision_account'),
'account_type' => $this->getRawOriginal('account_type'),
'decision_ground' => $this->getRawOriginal('decision_ground'),
'decision_ground_reference_url' => $this->getRawOriginal('decision_ground_reference_url'),
'content_type' => $this->getRawOriginal('content_type'),
'content_type_other' => $this->getRawOriginal('content_type_other'),
'content_language' => $this->getRawOriginal('content_language'),
'content_date' => $this->getRawOriginal('content_date'),
'application_date' => $this->getRawOriginal('application_date'),
'illegal_content_legal_ground' => $this->getRawOriginal('illegal_content_legal_ground'),
'illegal_content_explanation' => $this->getRawOriginal('illegal_content_explanation'),
'incompatible_content_ground' => $this->getRawOriginal('incompatible_content_ground'),
'incompatible_content_explanation' => $this->getRawOriginal('incompatible_content_explanation'),
'incompatible_content_illegal' => $this->getRawOriginal('incompatible_content_illegal'),
'source_type' => $this->getRawOriginal('source_type'),
'source_identity' => $this->getRawOriginal('source_identity'),
'decision_facts' => $this->getRawOriginal('decision_facts'),
'automated_detection' => $this->getRawOriginal('automated_detection'),
'automated_decision' => $this->getRawOriginal('automated_decision'),
'category' => $this->getRawOriginal('category'),
'category_addition' => $this->getRawOriginal('category_addition'),
'category_specification' => $this->getRawOriginal('category_specification'),
'category_specification_other' => $this->getRawOriginal('category_specification_other'),
'platform_id' => $this->getRawOriginal('platform_id'),
'user_id' => $this->getRawOriginal('user_id'),
'created_at' => $this->getRawOriginal('created_at'),
'updated_at' => $this->getRawOriginal('updated_at'),
'deleted_at' => $this->getRawOriginal('deleted_at'),
'puid' => $this->getRawOriginal('puid'),
'territorial_scope' => $this->getRawOriginal('territorial_scope'),
'method' => $this->getRawOriginal('method'),
'end_date' => $this->getRawOriginal('end_date'),
'end_date_visibility_restriction' => $this->getRawOriginal('end_date_visibility_restriction'),
'end_date_monetary_restriction' => $this->getRawOriginal('end_date_monetary_restriction'),
'end_date_service_restriction' => $this->getRawOriginal('end_date_service_restriction'),
'end_date_account_restriction' => $this->getRawOriginal('end_date_account_restriction'),
];
}

/**
* Get the value used to index the model.
*/
Expand Down
2 changes: 1 addition & 1 deletion app/Services/EuropeanCountriesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public function getOptionsArray(): array
public function filterSortEuropeanCountries(array $countries): array
{
$intersection = array_intersect($countries, self::EUROPEAN_COUNTRY_CODES) ?? [];
$filtered = array_unique($intersection);
$filtered = array_unique(array_values($intersection));
sort($filtered);
return $filtered;
}
Expand Down
9 changes: 9 additions & 0 deletions app/Services/GroupedSubmissionsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

class GroupedSubmissionsService
{
public function __construct(protected EuropeanCountriesService $european_countries_service)
{

}

public function sanitizePayloadStatement(&$payload_statement): void
{
Expand Down Expand Up @@ -47,8 +51,10 @@ public function sanitizePayloadStatement(&$payload_statement): void
}

/**
* @param array $payload_statement
* @param $field
* @param $needle
*
* @return void
*/
private function handleOtherFieldWithinArray(array &$payload_statement, $field, $needle): void
Expand Down Expand Up @@ -126,6 +132,8 @@ public function sanitizePayload(
$statement['decision_visibility'] ?? [], true);
$content_type_other_required = in_array('CONTENT_TYPE_OTHER', $statement['content_type'] ?? [], true);



// Create a new validator instance for each statement
$validator = Validator::make($statement,
$this->multi_rules($decision_visibility_other_required, $content_type_other_required),
Expand All @@ -138,6 +146,7 @@ public function sanitizePayload(

try {
$payload['statements'][$index] = $validator->validated();
$payload['statements'][$index]['territorial_scope'] = $this->european_countries_service->filterSortEuropeanCountries($payload['statements'][$index]['territorial_scope'] ?? []);
} catch (ValidationException) {
}
}
Expand Down
30 changes: 30 additions & 0 deletions config/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,36 @@
]) : [],
],

'mysqlpreprod' => [
'sticky' => true,
'driver' => 'mysql',
'url' => env('DATABASE_URL_PREPROD'),
'read' => [
'host' => [
env('DB_HOST_READER_PREPROD', env('DB_HOST_PREPROD', '127.0.0.1')),
],
],
'write' => [
'host' => [
env('DB_HOST_PREPROD', '127.0.0.1'),
],
],
'port' => env('DB_PORT_PREPROD', '3306'),
'database' => env('DB_DATABASE_PREPROD', 'forge'),
'username' => env('DB_USERNAME_PREPROD', 'forge'),
'password' => env('DB_PASSWORD_PREPROD', ''),
'unix_socket' => env('DB_SOCKET_PREPROD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA_PREPROD'),
]) : [],
],



'pgsql' => [
Expand Down
9 changes: 9 additions & 0 deletions resources/markdown/en/announcements.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
#### [Announcement – DB] Removing duplicated entries from the Transparency Database
<p class="ecl-u-type-paragraph" style="margin-top:-20px; font-style: italic !important">Published 14/05/2024</p>

On Wednesday 22 May 2024, the DSA Transparency Database (TDB) team will perform a data consistency check on the database in order to remove Statement of Reasons (SoR) that may have been either repeatedly or faultily submitted to the database. This is why the number of statements of reasons reported both in the dashboard and the descriptive statistics on the homepage is expected to significantly decrease once the data cleaning procedure is completed.

A following announcement will be published to flag that: i) the data consistency check is completed, and, ii) that the daily dumps' files have been recreated to reflect the cleaned content of the TDB.

<p class="ecl-u-type-paragraph" style="margin-top:54px; margin-bottom:24px"><hr/></p>

#### [Announcement - API] Restoring the 422 error for duplicated platform uid (puid)
<p class="ecl-u-type-paragraph" style="margin-top:-20px; font-style: italic !important">Published 08/04/2024</p>
On 8th of April 2024, the European Commission restored the 422 – Unprocessable Content error. The API endpoint will return the error whenever a platform is submitting a Statement of Reasons (SoR) containing a platform unique identifier (puid) already found in the SoR previously submitted to the database by the same platform.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,29 @@ public function it_should_store_multiple_submissions_created_by_factory(): void
$this->assertCount(15, Statement::all());
}

/**
* @test
*/
public function it_should_deduplicate_territories(): void
{
$user = $this->signInAsContributor();

$statements = $this->createFullStatements(5);
$statements[4]['territorial_scope'] = ['DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT','DE', 'ES', 'PT'];

$response = $this->post(route('api.v1.statements.store'), [
"statements" => $statements
], [
'Accept' => 'application/json'
]);
$response->assertStatus(Response::HTTP_CREATED);

$this->assertCount(15, Statement::all());
$last = Statement::orderBy('id', 'desc')->first();
$territorial_scope = $last->territorial_scope;
$this->assertEquals(["DE", "ES", "PT"], $territorial_scope);
}

/**
* @test
*/
Expand Down
20 changes: 20 additions & 0 deletions tests/Feature/Models/StatementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use App\Models\Statement;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;

class StatementTest extends TestCase
Expand Down Expand Up @@ -61,6 +62,25 @@ public function territorial_scope_is_always_sorted(): void
$statement->save();
$statement->refresh();

// Get it back in alpha order
$territorial_scope = $statement->territorial_scope;
$this->assertEquals(["AU", "BE", "SK"], $territorial_scope);
}

/**
* @return void
* @test
*/
public function territorial_scope_is_always_unique(): void
{
$statement = Statement::all()->random()->first();

// Store in non alpha order
$statement->territorial_scope = ['SK', 'BE', 'AU', 'SK', 'BE', 'AU', 'SK', 'BE', 'AU', 'SK', 'BE', 'AU', 'AU', 'AU', 'AU'];
$statement->save();
$statement->refresh();


// Get it back in alpha order
$territorial_scope = $statement->territorial_scope;
$this->assertEquals(["AU", "BE", "SK"], $territorial_scope);
Expand Down
Loading

0 comments on commit 50c3612

Please sign in to comment.