Compare commits

..

68 commits

Author SHA1 Message Date
Noah Lancien
5a15a5713f Merge branch 'trunk' 2025-12-01 09:12:22 +01:00
Noah Lancien
324841b778 Merge branch 'develop' into trunk 2025-12-01 09:11:52 +01:00
noah.lancien
42faaf51bb Merge branch '28-code-article' into 'develop'
fix: adding an article code to a media was broken #28

See merge request ldc-web/projets/dam!10
2025-12-01 08:09:29 +00:00
Noah Lancien
6f5a7dae69 fix: remove useless parts from previous commit 2025-11-28 17:31:54 +01:00
Noah Lancien
0f74b496ab fix: adding an article code to a media was broken #28 2025-11-28 17:20:03 +01:00
Vincent BRIDIER
286d3adc6b Merge branch 'trunk' 2025-11-19 15:07:56 +01:00
Vincent BRIDIER
748597277e Merge branch 'develop' into trunk 2025-11-19 15:07:48 +01:00
Vincent BRIDIER
20e5a325ff fix: some fixes 2025-11-19 15:07:39 +01:00
Vincent BRIDIER
ea692f98ac Merge branch 'trunk' 2025-11-19 15:03:03 +01:00
Vincent BRIDIER
931c53d76a Merge branch 'develop' into trunk 2025-11-19 15:02:55 +01:00
Vincent BRIDIER
a73bcc2b4b fix: some fixes 2025-11-19 15:02:45 +01:00
Vincent BRIDIER
05e1d60159 Merge branch 'trunk' 2025-11-19 14:28:31 +01:00
Vincent BRIDIER
9c2a3fb82e Merge branch 'develop' into trunk 2025-11-19 14:28:22 +01:00
Vincent BRIDIER
6c90845c4c fix: some fixes 2025-11-19 14:27:59 +01:00
Vincent BRIDIER
4976f1cac9 Merge branch 'block-arcadia-link-for-drafts' into 'develop'
feat: block arcadia link request when the media is in draft status

See merge request ldc-web/projets/dam!9
2025-11-19 13:20:20 +00:00
Noah Lancien
116f465849 feat: block arcadia link request when the media is in draft status 2025-11-19 11:20:01 +01:00
Vincent BRIDIER
840c3ea475
fix: Fix media link on ArcadiaLink 2025-11-17 17:31:56 +01:00
Vincent BRIDIER
7a9c8f4da3
fix: Fix xml generation on ArcadiaLink 2025-11-17 17:06:38 +01:00
Vincent BRIDIER
dbb92dd6ed
fix: Fix variante field - Close #27 2025-11-17 16:00:34 +01:00
Vincent BRIDIER
23147b209e Merge branch '24-alphabetical-order-for-user-list' into 'develop'
feat: order by alphabetical ASC the user list in delete page

See merge request ldc-web/projets/dam!7
2025-10-28 12:06:40 +00:00
Noah Lancien
763ace7667 feat: order by alphabetical ASC the user list in delete page 2025-10-28 09:49:12 +01:00
Vincent BRIDIER
241adfeb50
Merge branch 'trunk' 2025-10-27 16:08:03 +01:00
Vincent BRIDIER
9f3b536bf7
Merge branch 'develop' into trunk 2025-10-27 16:07:54 +01:00
Vincent BRIDIER
b6338d4574
fix: Fix folders regressions in controller 2025-10-27 16:07:44 +01:00
Vincent BRIDIER
485e66c137
Merge branch 'trunk' 2025-10-24 12:25:26 +02:00
Vincent BRIDIER
ac9dbc3aad
Merge branch 'develop' into trunk 2025-10-24 12:25:07 +02:00
Vincent BRIDIER
3d1e08c664
Merge branch 'develop' of lab.s-web.fr:ldc-web/projets/dam into develop 2025-10-24 12:22:53 +02:00
Vincent BRIDIER
1a64f7b0d2
feat: Remove ldc web status checker deps + composer update 2025-10-24 12:15:28 +02:00
Vincent BRIDIER
f3c97443a6
feat: Add auth bypass feature for local dev 2025-10-24 12:15:01 +02:00
Vincent BRIDIER
5a25b0ba21
fix: Fix Media model event triggering 2025-10-24 12:06:58 +02:00
Vincent BRIDIER
b7392ec487
fix: Fix arcadia:import command 2025-10-24 11:19:49 +02:00
Noah Lancien
43ae1cb818 Merge branch 'trunk' 2025-06-04 15:18:47 +02:00
Noah Lancien
3b8cb4c5ae Merge branch 'develop' into trunk 2025-05-07 14:42:28 +02:00
noah.lancien
82368e2dd3 Merge branch 're7-feedback' into 'develop'
fix: folder filter now reset when the subject is updated

See merge request ldc-web/projets/dam!6
2025-05-07 12:41:56 +00:00
Noah Lancien
925dc2a495 fix: folder filter now reset when the subject is updated 2025-05-07 12:40:45 +02:00
Noah Lancien
b1763e5db3 Merge branch 'develop' into trunk 2025-05-06 12:08:43 +02:00
noah.lancien
e0870d362e Merge branch 'multiple-fixes' into 'develop'
Issues 6,7,8,9,10,12,13

See merge request ldc-web/projets/dam!4
2025-05-06 10:07:55 +00:00
Noah Lancien
0984fa00b7 fix: many fixes from develop branch + new re7 feedbacks 2025-05-06 12:05:18 +02:00
Jérémy Munsch
ad00dd2246 Reset Media route resolv using uid (besoin métier) vu avec Vincent 2025-05-06 11:10:16 +02:00
Jérémy Munsch
3dce58d9a0 Fixes #12 Fixed MediaController::esFilters arcadia_id fetch from filters issue 2025-05-06 11:10:16 +02:00
Jérémy Munsch
0194d8e0c1 Fix Media duplicate
- put in transaction
- set arcadia_id to null
2025-05-06 11:10:13 +02:00
Jérémy Munsch
14aeec5e2a Fixes #10
- Remove explicition resolve for media in RouteServicePRovider
- Set usage of media id on media routes everywhere
2025-05-06 11:02:02 +02:00
Jérémy Munsch
eb212215a8 Fixes #9
- add FK on arcadia_links to media.id and remove orphans
- Refactored ArcadiaLinkController
- Added comments on ArcadiaLink model
- refactored arcadialinks.index
2025-05-06 11:02:02 +02:00
Jérémy Munsch
c5d8ea542f Add View service provider (prepare to bump slowly) 2025-05-06 11:02:02 +02:00
Jérémy Munsch
50832db21b Fixes #8+
Enums arent using BaseEnum trait and cannot since tool low php level, need to manually implement behaviors
2025-05-06 11:02:02 +02:00
Jérémy Munsch
c6eaf2f12b MediaController refactor getMediaOtherInfos 2025-05-06 11:02:02 +02:00
Jérémy Munsch
8651a5cc2a Fixes #7,#13 REfactor BasektController + Flush cache before querying basket media list 2025-05-06 11:02:00 +02:00
Jérémy Munsch
bc4a8f64ae Fixes #6 2025-05-06 11:01:28 +02:00
Jérémy Munsch
d62b1d513f UploadController fix Media query 2025-05-06 11:01:26 +02:00
Jérémy Munsch
f6dc577255 Add TODO in config/roles 2025-05-06 11:00:15 +02:00
Jérémy Munsch
80615fe61a Add Model User comments 2025-05-06 11:00:15 +02:00
Jérémy Munsch
92d837586e MediaController::loadMedia refactor 2025-05-06 11:00:14 +02:00
Jérémy Munsch
e18918fa61 Dossier model refactor getMediacountAttribute 2025-05-06 10:59:23 +02:00
Jérémy Munsch
156c4a6317 DossierController refactor with typehint 2025-05-06 10:59:23 +02:00
Jérémy Munsch
20c1d2da6f .gitignore update 2025-05-06 10:59:23 +02:00
Jérémy Munsch
d0778093d5 npm update 2025-05-06 10:59:23 +02:00
Jérémy Munsch
39a28c5e3f composer update 2025-05-06 10:59:23 +02:00
Jérémy Munsch
d41acba6c5 add name to package json 2025-05-06 10:59:23 +02:00
Jérémy Munsch
c9be7205be update client api + add .gitmodules 2025-05-06 10:59:23 +02:00
Noah Lancien
d34a9a4624 Merge branch 'develop' into trunk 2025-03-25 16:18:55 +01:00
noah.lancien
29f8dfd724 Merge branch 'issue-20-re7-feedback' into 'develop'
fix: many bug fixes - #20

See merge request ldc-web/projets/dam!5
2025-03-25 15:17:09 +00:00
Noah Lancien
58287ae7bc Merge branch 'develop' into trunk 2025-03-25 16:17:00 +01:00
Noah Lancien
98cbbe5b93 fix: review feedbacks 2025-03-25 15:23:44 +01:00
Noah Lancien
e39f4e8146 feat: added a link to media manager in the home page 2025-03-25 11:24:59 +01:00
Noah Lancien
caa7189cc3 fix: many bug fixes - #20 2025-03-25 11:00:14 +01:00
Vincent BRIDIER
42f28abe33
Merge branch 'develop' into trunk 2023-11-24 09:42:12 +01:00
Jérémy Munsch
d343d87486
Merge branch 'hotfix' 2022-10-26 12:59:57 +02:00
Jérémy Munsch
592bd9bdaa
Merge branch 'hotfix' 2022-10-26 12:45:49 +02:00
45 changed files with 1862 additions and 1634 deletions

View file

@ -60,4 +60,4 @@ MAIL_LIST_SERVICEWEB=
PROJECT_UUID= PROJECT_UUID=
## MAIL ADDRESSES ## MAIL ADDRESSES
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr MAIL_LIST_SERVICEWEB=digital@ldc.fr

View file

@ -39,7 +39,7 @@ MAIL_PASSWORD=
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=no-reply@dam.lesidc.com MAIL_FROM_ADDRESS=no-reply@dam.lesidc.com
MAIL_FROM_NAME="${APP_NAME}" MAIL_FROM_NAME="${APP_NAME}"
MAIL_ADMIN=equipe.web@ldc.fr MAIL_ADMIN=digital@ldc.fr
LDAP_ACCOUNT_PREFIX="cn=" LDAP_ACCOUNT_PREFIX="cn="
@ -54,7 +54,7 @@ LDAP_USE_SSL=false
PROJECT_UUID= PROJECT_UUID=
## MAIL ADDRESSES ## MAIL ADDRESSES
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr MAIL_LIST_SERVICEWEB=digital@ldc.fr
LDC_STATUS_CHECKER_API_KEY=CE8S52Qq7stf5k8frF4T LDC_STATUS_CHECKER_API_KEY=CE8S52Qq7stf5k8frF4T
LDC_STATUS_CHECKER_UUID=4d8b2c20-107a-4682-b591-dc6c685126df LDC_STATUS_CHECKER_UUID=4d8b2c20-107a-4682-b591-dc6c685126df

View file

@ -39,7 +39,7 @@ MAIL_PASSWORD=
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=no-reply@dam.lesidc.com MAIL_FROM_ADDRESS=no-reply@dam.lesidc.com
MAIL_FROM_NAME="${APP_NAME}" MAIL_FROM_NAME="${APP_NAME}"
MAIL_ADMIN=equipe.web@ldc.fr MAIL_ADMIN=digital@ldc.fr
LDAP_ACCOUNT_PREFIX= LDAP_ACCOUNT_PREFIX=
@ -54,7 +54,7 @@ LDAP_USE_SSL=
PROJECT_UUID= PROJECT_UUID=
## MAIL ADDRESSES ## MAIL ADDRESSES
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr MAIL_LIST_SERVICEWEB=digital@ldc.fr
LDC_STATUS_CHECKER_API_KEY= LDC_STATUS_CHECKER_API_KEY=
LDC_STATUS_CHECKER_UUID= LDC_STATUS_CHECKER_UUID=

View file

@ -25,7 +25,7 @@ php artisan key:generate
.env => remplacer MAIL_DRIVER par MAIL_MAILER .env => remplacer MAIL_DRIVER par MAIL_MAILER
.env => remplacer FILESYSTEM_DRIVER par FILESYSTEM_DISK .env => remplacer FILESYSTEM_DRIVER par FILESYSTEM_DISK
.env rajouter PROJECT_UUID= .env rajouter PROJECT_UUID=
.env rajouter MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr .env rajouter MAIL_LIST_SERVICEWEB=digital@ldc.fr
# SUPERVISOR # SUPERVISOR
jobs Api stats sur queue `database` jobs Api stats sur queue `database`

View file

@ -127,20 +127,20 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->dam as $row) { foreach ($fileContent->dam as $row) {
/** @var \App\Models\Article|null $record */ /** @var \App\Models\Article|null $record */
$record = Article::where('noArt', $row->noArt)->first(); $record = Article::where('noArt', (int)$row->noArt)->first();
if (!$record) { if (!$record) {
$record = new Article(); $record = new Article();
$record->noArt = $row->noArt; $record->noArt = (int)$row->noArt;
} }
$record->libCcial = $row->libCcial; $record->libCcial = (string)$row->libCcial;
$record->codMarq = $row->codMarq; $record->codMarq = (int)$row->codMarq;
$record->libMarq = $row->libMarq; $record->libMarq = (string)$row->libMarq;
$record->codFamVte = $row->codFamVte; $record->codFamVte = (int)$row->codFamVte;
$record->libFamVte = $row->libFamVte; $record->libFamVte = (string)$row->libFamVte;
$record->codGencodAdm = $row->codGencodAdm; $record->codGencodAdm = (string)$row->codGencodAdm;
$record->codGencodSymb = $row->codGencodSymb; $record->codGencodSymb = (string)$row->codGencodSymb;
$record->codGencodPds = $row->codGencodPds; $record->codGencodPds = (string)$row->codGencodPds;
$record->utilisableGroupe = $row->utilisableGroupe; $record->utilisableGroupe = (int)$row->utilisableGroupe;
$record->saveOrFail(); $record->saveOrFail();
} //end foreach } //end foreach
} }
@ -157,12 +157,12 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->dam as $row) { foreach ($fileContent->dam as $row) {
/** @var \App\Models\Marque|null $record */ /** @var \App\Models\Marque|null $record */
$record = Marque::where('codMarq', $row->codMarq)->first(); $record = Marque::where('codMarq', (int)$row->codMarq)->first();
if (!$record) { if (!$record) {
$record = new Marque(); $record = new Marque();
$record->codMarq = $row->codMarq; $record->codMarq = (int)$row->codMarq;
} }
$record->libMarq = $row->libMarq; $record->libMarq = (string)$row->libMarq;
$record->saveOrFail(); $record->saveOrFail();
} }
} }
@ -179,12 +179,12 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->mediaSujet as $row) { foreach ($fileContent->mediaSujet as $row) {
/** @var \App\Models\Sujet|null $record */ /** @var \App\Models\Sujet|null $record */
$record = Sujet::where('codeSujet', $row->code)->first(); $record = Sujet::where('codeSujet', (int)$row->code)->first();
if (!$record) { if (!$record) {
$record = new Sujet(); $record = new Sujet();
$record->codeSujet = $row->code; $record->codeSujet = (int)$row->code;
} }
$record->libelle = $row->libelle; $record->libelle = (string)$row->libelle;
$record->saveOrFail(); $record->saveOrFail();
} }
} }
@ -201,12 +201,12 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->mediatypemedia as $row) { foreach ($fileContent->mediatypemedia as $row) {
/** @var \App\Models\TypeMedia|null $record */ /** @var \App\Models\TypeMedia|null $record */
$record = TypeMedia::where('codeTypemedia', $row->code)->first(); $record = TypeMedia::where('codeTypemedia', (int)$row->code)->first();
if (!$record) { if (!$record) {
$record = new TypeMedia(); $record = new TypeMedia();
$record->codeTypemedia = $row->code; $record->codeTypemedia = (int)$row->code;
} }
$record->libelle = $row->libelle; $record->libelle = (string)$row->libelle;
$record->saveOrFail(); $record->saveOrFail();
} }
} }
@ -223,13 +223,13 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->mediatypesvue as $row) { foreach ($fileContent->mediatypesvue as $row) {
/** @var \App\Models\TypeVue|null $record */ /** @var \App\Models\TypeVue|null $record */
$record = TypeVue::where('codeTypevue', $row->code)->first(); $record = TypeVue::where('codeTypevue', (int)$row->code)->first();
if (!$record) { if (!$record) {
$record = new TypeVue(); $record = new TypeVue();
$record->codeTypevue = $row->code; $record->codeTypevue = (int)$row->code;
} }
$record->libelle = $row->libelle; $record->libelle = (string)$row->libelle;
$record->sujet_id = $row->sujet_id->mediasujet->code; $record->sujet_id = (int)$row->sujet_id->mediasujet->code;
$record->saveOrFail(); $record->saveOrFail();
} }
} }
@ -246,14 +246,14 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->mediavariante as $row) { foreach ($fileContent->mediavariante as $row) {
/** @var \App\Models\TypeVue|null $record */ /** @var \App\Models\TypeVue|null $record */
$record = Variante::where('codeVariante', $row->code)->first(); $record = Variante::where('codeVariante', (int)$row->code)->first();
if (!$record) { if (!$record) {
$record = new Variante(); $record = new Variante();
$record->codeVariante = $row->code; $record->codeVariante = (int)$row->code;
} }
$record->libelle = $row->libelle; $record->libelle = (string)$row->libelle;
$record->sujet_id = $row->sujet_id->children()[0]->code; $record->sujet_id = (int)$row->sujet_id->children()[0]->code;
$record->type_vue_id = $row->CodeTypeVue->mediatypesvue->code; $record->type_vue_id = (int)$row->CodeTypeVue->mediatypesvue->code;
$record->saveOrFail(); $record->saveOrFail();
} }
} }
@ -270,12 +270,12 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->SITE_PROD_GRP as $row) { foreach ($fileContent->SITE_PROD_GRP as $row) {
/** @var \App\Models\TypeVue|null $record */ /** @var \App\Models\TypeVue|null $record */
$record = Site::where('id', $row->code)->first(); $record = Site::where('id', (int)$row->code)->first();
if (!$record) { if (!$record) {
$record = new Site(); $record = new Site();
$record->id = $row->code; $record->id = (int)$row->code;
} }
$record->libelle = $row->libelle; $record->libelle = (string)$row->libelle;
$record->saveOrFail(); $record->saveOrFail();
} }
} }
@ -292,12 +292,12 @@ class ImportArcadiaModelFiles extends Command
/** @var \SimpleXMLElement $row */ /** @var \SimpleXMLElement $row */
foreach ($fileContent->dam as $row) { foreach ($fileContent->dam as $row) {
/** @var \App\Models\TypeVue|null $record */ /** @var \App\Models\TypeVue|null $record */
$record = Societe::where('id', $row->codSociete)->first(); $record = Societe::where('id', (int)$row->codSociete)->first();
if (!$record) { if (!$record) {
$record = new Societe(); $record = new Societe();
$record->id = $row->codSociete; $record->id = (int)$row->codSociete;
} }
$record->libelle = $row->nomSociete; $record->libelle = (string)$row->nomSociete;
$record->saveOrFail(); $record->saveOrFail();
} }
} }

View file

@ -0,0 +1,54 @@
<?php
namespace App\Console\Commands;
use App\Lib\ArcadiaLinkUtilities;
use App\Models\ArcadiaLink;
use App\Models\Media;
use Illuminate\Console\Command;
class ResendArcadiaLinkMedias extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'medias:resend-aracadia-links';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Resend files to Arcadia after Arcadia Link fix';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
// FIXME : Variabiliser la date
//$al = ArcadiaLink::where('created_at', '>=', '2025-10-23')->get();
foreach ($al as $error)
{
$media = Media::withTrashed()->find($error->media_id);
if ($error->arcadia_id === 0) {
ArcadiaLinkUtilities::create($media);
} else {
if (is_null($media->deleted_at)) {
ArcadiaLinkUtilities::update($media);
} else {
ArcadiaLinkUtilities::delete($media);
}
}
}
return Command::SUCCESS;
}
}

View file

@ -3,7 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\ArcadiaLink; use App\Models\ArcadiaLink;
use Illuminate\Support\Carbon; use Illuminate\Contracts\Database\Eloquent\Builder;
class ArcadiaLinkController extends Controller class ArcadiaLinkController extends Controller
{ {
@ -17,9 +17,14 @@ class ArcadiaLinkController extends Controller
/** @var \App\Models\User */ /** @var \App\Models\User */
$user = auth()->user(); $user = auth()->user();
$user->authorizeRoles(config('roles.const.ADMIN')); $user->authorizeRoles(config('roles.const.ADMIN'));
$dt = Carbon::now('Europe/Paris')->subMinutes(15)->toDateTimeString();
$ano = ArcadiaLink::where('created_at', '<', $dt)->orderBy('id', 'DESC')->get(); // * ArcadiaLink->Media is nullable
return view('arcadialinks.index', ['ano' => $ano]); $arcadiaLinkList = ArcadiaLink::query()
->with('media', fn (Builder $q) => $q->withTrashed())
->where('created_at', '<', now()->subMinutes(15))
->orderBy('id', 'DESC')->get();
return view('arcadialinks.index', compact('arcadiaLinkList'));
} }
/** /**

View file

@ -39,7 +39,8 @@ class CommonController extends Controller
})->with('sujet')->get(); })->with('sujet')->get();
return view('home')->with([ return view('home')->with([
'sujets' => $sujets, 'recherches' => $recherches, 'sujets' => $sujets,
'recherches' => $recherches,
'dossiers' => $dossiers 'dossiers' => $dossiers
]); ]);
} }
@ -54,8 +55,10 @@ class CommonController extends Controller
{ {
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
Mail::to(env('MAIL_ADMIN_ADDRESS', "informatique.internet@ldc.fr")) foreach (config('mail.contactsList.admin') as $mail) {
Mail::to($mail)
->send(new ContactMail(ContactType::from($request->type), $request->url, $request->message, $user)); ->send(new ContactMail(ContactType::from($request->type), $request->url, $request->message, $user));
}
return response()->json(['status' => 'OK']); return response()->json(['status' => 'OK']);
} }

View file

@ -19,6 +19,7 @@ use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -42,7 +43,7 @@ class DossierController extends Controller
$publicFolders = Dossier::query() $publicFolders = Dossier::query()
->whereHas('sujet', fn (Builder $q) => $q->where('codeSujet', $request->input('sujet_id'))) ->whereHas('sujet', fn (Builder $q) => $q->where('codeSujet', $request->input('sujet_id')))
->where('is_private', false) ->where('is_private', false)
->whereDoesntHave('dossierParent') ->whereNull('parent_id')
->select($select)->get(); ->select($select)->get();
@ -74,23 +75,29 @@ class DossierController extends Controller
// * Ajout du dépôt de fichier pour les admin. // * Ajout du dépôt de fichier pour les admin.
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> Dossiers depots */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> Dossiers depots */
$depotQuery = Dossier::query() $depotQuery = Dossier::query()
->whereDoesntHave('dossierParent') ->whereNull('parent_id')
->where('system', true) ->where('system', true)
->orderBy('libelle', 'ASC') ->orderBy('libelle', 'ASC')
->get(); ->get();
$foldersCollection = $foldersCollection->merge($depotQuery); $foldersCollection = $foldersCollection->merge($depotQuery);
} }
$folders['data'] = new NestedDossiersListResource($foldersCollection); Arr::set($folders, 'data', new NestedDossiersListResource($foldersCollection));
$folders['racineCount'] = Media::query()
->whereHas('sujet', fn (Builder $q) => $q->where('id', $request->input('sujet_id'))) // * Racine Count
->whereDoesntHave('dossier') $racineCountQuery = Media::query()
->where( ->whereHas('sujet', fn (Builder $q) => $q->where('codeSujet', $request->input('sujet_id')))
->whereDoesntHave('dossier');
// ? Is not admin ?
if (!$user->hasRole(config('roles.const.ADMIN'))) {
$racineCountQuery->where(
fn (Builder $q) => fn (Builder $q) =>
$q->where('statut', MediaStatut::public_etendu) $q->where('statut', MediaStatut::public_etendu)
->orWhere('statut', MediaStatut::public) ->orWhere('statut', MediaStatut::public)
->orWhere('created_by', $user->id) ->orWhere('created_by', $user->id)
)->count(); );
}
Arr::set($folders, 'racineCount', $racineCountQuery->count());
return response()->json($folders); return response()->json($folders);
} }
@ -108,7 +115,7 @@ class DossierController extends Controller
$response = []; $response = [];
$response['variantes'] = Variante::query() $response['variantes'] = Variante::query()
->whereHas('sujet', fn (Builder $q) => $q->where('id', $request->input('sujetId'))) ->whereHas('sujet', fn (Builder $q) => $q->where('codeSujet', $request->input('sujetId')))
->get(); ->get();
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Format> */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Format> */
$FormatsSujet = Format::query() $FormatsSujet = Format::query()
@ -143,7 +150,7 @@ class DossierController extends Controller
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> */
$dossiers = Dossier::query() $dossiers = Dossier::query()
->whereDoesntHave('dossierParent') ->whereNull('parent_id')
->where('system', false) ->where('system', false)
->orderBy('libelle', 'asc') ->orderBy('libelle', 'asc')
->get(); ->get();
@ -167,7 +174,7 @@ class DossierController extends Controller
if ($request->sub) { if ($request->sub) {
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> */
$dossiers = Dossier::query() $dossiers = Dossier::query()
->whereDoesntHave('dossierParent') ->whereNull('parent_id')
->where('system', false) ->where('system', false)
->orderBy('libelle', 'asc')->get(); ->orderBy('libelle', 'asc')->get();
return view('dossiers.create-sub', [ return view('dossiers.create-sub', [

View file

@ -34,11 +34,12 @@ use App\Models\Sujet;
use App\Models\Tag; use App\Models\Tag;
use App\Models\TypeMedia; use App\Models\TypeMedia;
use App\Traits\Http\HandlesMedia; use App\Traits\Http\HandlesMedia;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
@ -65,6 +66,8 @@ class MediaController extends Controller
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Sujet> */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Sujet> */
$sujets = $user->sujets; $sujets = $user->sujets;
// ! Has to flush Media cache before querying basket with media list
Media::flushQueryCache();
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Panier> */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Panier> */
$paniers = $user->paniersOwner; $paniers = $user->paniersOwner;
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Societe> */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Societe> */
@ -124,7 +127,7 @@ class MediaController extends Controller
'etiquettes' => $etiquettes, 'etiquettes' => $etiquettes,
'societes' => $societes, 'societes' => $societes,
'marques' => $marques, 'marques' => $marques,
'currentFolder' => $dossier_id, 'currentFolder' => Dossier::query()->where('id', $dossier_id)->first() ?? $dossier_id,
'currentSujet' => optional($sujet)->codeSujet ?? \optional($sujets->first())->codeSujet, 'currentSujet' => optional($sujet)->codeSujet ?? \optional($sujets->first())->codeSujet,
'currentFilters' => json_encode($filters), 'currentFilters' => json_encode($filters),
'paniers' => $paniers, 'paniers' => $paniers,
@ -156,12 +159,16 @@ class MediaController extends Controller
$user = auth()->user(); $user = auth()->user();
/** @var \App\Models\Dossier|null */ /** @var \App\Models\Dossier|null */
$dossier = Dossier::where('id', $request->folder)->first(); $dossier = Dossier::query()
->with('dossierParent')
->where('id', $request->input('folder'))
->first();
$response = []; $response = [];
$filters = (object)collect($request->filters)->all(); $filters = (object)collect($request->input('filters'))->all();
$isDepot = ($dossier->parent_id ?? null) === 1 || ($dossier->id ?? null) === 1; /** @var boolean Est un dossier Dépot ? */
$isDepot = !empty($dossier) && (\optional($dossier->dossierParent)->id === 1 || $dossier->id === 1);
/** /**
* Elastic Search must conditions * Elastic Search must conditions
@ -205,7 +212,6 @@ class MediaController extends Controller
$esMust, $esMust,
$esMustNot, $esMustNot,
$esShould, $esShould,
$esFilters,
$request, $request,
$dossier, $dossier,
$sujet, $sujet,
@ -220,26 +226,30 @@ class MediaController extends Controller
'bool.should' => $esShould, 'bool.should' => $esShould,
'bool.filter' => $esFilters, 'bool.filter' => $esFilters,
]); ]);
$sort = [[$orderField => ['order' => $order]]]; $sort = [[$orderField => ['order' => $order]]];
$response['data'] = Media::searchByQuery( Arr::set($response, 'data', Media::searchByQuery(
$query, $query,
null, null,
null, null,
intval($request->post('limit', 50)), intval($request->post('limit', 50)),
intval($request->post('offset', 0)), intval($request->post('offset', 0)),
$sort $sort
); ));
$response['draggable'] = $user->hasRole([config('roles.const.ADMIN'), config('roles.const.REDACTEUR')]); Arr::set($response, 'draggable', $user->hasRole([
$response['isDepot'] = $isDepot; config('roles.const.ADMIN'),
config('roles.const.REDACTEUR')
$response['isCAQuery'] = $searchText && ]));
Arr::set($response, 'isDepot', $isDepot);
Arr::set(
$response,
'isCAQuery',
$searchText &&
strpos($searchText, '=') !== false && strpos($searchText, '=') !== false &&
\strval(collect(explode('=', $searchText))->get(0)) === 'ca'; \strval(collect(explode('=', $searchText))->get(0)) === 'ca'
);
$response['role'] = $user->role; Arr::set($response, 'role', $user->role);
return \response()->json($response); return \response()->json($response);
} }
@ -346,7 +356,7 @@ class MediaController extends Controller
}); });
} catch (ModelNotFoundException | \RuntimeException $e) { } catch (ModelNotFoundException | \RuntimeException $e) {
return response()->json($e->getMessage(), 500); return response()->json($e->getMessage(), 500);
}//end try } //end try
} }
/** /**
@ -397,6 +407,7 @@ class MediaController extends Controller
// ---- Les articles // ---- Les articles
$media->articles()->sync(collect($request->articles)->pluck('id')->all()); $media->articles()->sync(collect($request->articles)->pluck('id')->all());
Article::flushQueryCache();
$media->saveOrFail(); $media->saveOrFail();
@ -416,7 +427,7 @@ class MediaController extends Controller
'status' => false, 'status' => false,
'error' => trans('Une erreur est survenue veuillez réessayer') 'error' => trans('Une erreur est survenue veuillez réessayer')
]); ]);
}//end try } //end try
} }
/** /**
@ -428,6 +439,7 @@ class MediaController extends Controller
*/ */
public function duplicateMedia(Media $media): JsonResponse public function duplicateMedia(Media $media): JsonResponse
{ {
return DB::transaction(function () use ($media) {
/** @var \App\Models\User */ /** @var \App\Models\User */
$user = auth()->user(); $user = auth()->user();
@ -446,18 +458,8 @@ class MediaController extends Controller
$clonedMedia = $media->replicate(); $clonedMedia = $media->replicate();
$media->articles->map(function (Article $article) use ($clonedMedia) { // * Remove Arcadia ID (cloned is not linked to arcadia)
$clonedMedia->articles()->attach($article); $clonedMedia->arcadia_id = null;
});
$media->marques->map(function (Marque $marque) use ($clonedMedia) {
$clonedMedia->marques()->attach($marque);
});
$media->societes->map(function (Societe $societe) use ($clonedMedia) {
$clonedMedia->societes()->attach($societe);
});
$media->tags->map(function (Tag $tag) use ($clonedMedia) {
$clonedMedia->tags()->attach($tag);
});
/** @var \Illuminate\Filesystem\FilesystemAdapter */ /** @var \Illuminate\Filesystem\FilesystemAdapter */
$storage = Storage::disk('media'); $storage = Storage::disk('media');
@ -498,7 +500,23 @@ class MediaController extends Controller
// ---- Creation des vignettes en lien avec le sujet du média // ---- Creation des vignettes en lien avec le sujet du média
$clonedMedia->createSubjectThumbnails(); $clonedMedia->createSubjectThumbnails();
$clonedMedia->saveOrFail(); $clonedMedia->isDuplicate = true;
$clonedMedia->save();
// * Add relations after having a media id
$media->articles->map(function (Article $article) use ($clonedMedia) {
$clonedMedia->articles()->attach($article);
});
$media->marques->map(function (Marque $marque) use ($clonedMedia) {
$clonedMedia->marques()->attach($marque);
});
$media->societes->map(function (Societe $societe) use ($clonedMedia) {
$clonedMedia->societes()->attach($societe);
});
$media->tags->map(function (Tag $tag) use ($clonedMedia) {
$clonedMedia->tags()->attach($tag);
});
/** @throws \RuntimeException */ /** @throws \RuntimeException */
@ -512,6 +530,7 @@ class MediaController extends Controller
'sujet_id' => $clonedMedia->sujet_id, 'sujet_id' => $clonedMedia->sujet_id,
'datas' => $clonedMedia 'datas' => $clonedMedia
]); ]);
});
} }
/** /**
@ -641,6 +660,12 @@ class MediaController extends Controller
]); ]);
} }
if ($media->statut === MediaStatut::brouillon) {
throw ValidationException::withMessages([
'media' => trans('Ce média n\'est pas publié. Veuillez sauvegarder pour enregistrer le statut.')
]);
}
MediaLinkWithArcadia::dispatch($user, $media); MediaLinkWithArcadia::dispatch($user, $media);
return response()->json(true); return response()->json(true);
@ -744,15 +769,16 @@ class MediaController extends Controller
*/ */
public function getMediaOtherInfos(Media $media): JsonResponse public function getMediaOtherInfos(Media $media): JsonResponse
{ {
if (!($user = Auth::user())) { if (!auth()->check()) {
abort(401, 'Cette action n\'est pas autorisée.'); abort(401, 'Cette action n\'est pas autorisée.');
} }
$history = Historique::whereHas('media', function ($q) use ($media) { $history = Historique::query()
$q->whereId($media->id); ->whereHas('media', fn(Builder $q) => $q->where('id', $media->id))
})->with('user') ->with('user')
->orderBy('created_date', 'DESC') ->orderBy('created_date', 'DESC')
->get(); ->get();
return \response()->json([ return \response()->json([
'history' => $history, 'history' => $history,
'vignettes' => $this->getVignettesByMedia($media) 'vignettes' => $this->getVignettesByMedia($media)
@ -791,7 +817,7 @@ class MediaController extends Controller
/** @var boolean */ /** @var boolean */
$arcadia_id = collect($filters)->reduce(function (string|null $carry, array $item) { $arcadia_id = collect($filters)->reduce(function (string|null $carry, array $item) {
$item = collect($item); $item = collect($item);
return $carry ?? ($carry or $item->get('type') === 'arcadia_id' ? true : false); return ($carry ?? false) or ($item->get('type') === 'arcadia_id' ? true : false);
}); });
$esConditions = []; $esConditions = [];
@ -825,21 +851,21 @@ class MediaController extends Controller
/** /**
* Elastic Search select appropriate Folder * Elastic Search select appropriate Folder
* *
* @param array $esMust * @param array $esMust ES conditions INCLURE TOUT (AND).
* @param array $esMustNot * @param array $esMustNot ES conditions EXCLURE.
* @param array $esShould * @param array $esShould ES conditions INCLURE AU MOINS (OR), avec un score.
* @param array $esFilters * @param \App\Http\Requests\Bo\LoadMediaRequest $request La request Lrvl.
* @param \App\Http\Requests\Bo\LoadMediaRequest $request * @param \App\Models\Dossier|null $dossier Le dossier concerné, si les Medias
* @param \App\Models\Dossier|null $dossier * doivent appartenir a celui-ci.
* @param \App\Models\Sujet $sujet * @param \App\Models\Sujet $sujet Le sujet concerné, si les Medias
* @param boolean $isDepot * doivent appartenir a celui-ci.
* @param boolean $isDepot Si les medias doivent se trouver dans le dossier dépot.
* @return void * @return void
*/ */
private function esFolderSearch( private function esFolderSearch(
array &$esMust, array &$esMust,
array &$esMustNot, array &$esMustNot,
array &$esShould, array &$esShould,
array &$esFilters,
LoadMediaRequest $request, LoadMediaRequest $request,
Dossier|null $dossier, Dossier|null $dossier,
Sujet $sujet, Sujet $sujet,
@ -848,6 +874,7 @@ class MediaController extends Controller
/** @var \App\Models\User */ /** @var \App\Models\User */
$user = auth()->user(); $user = auth()->user();
// ? Doivent être dans le dossier dépot ?
if ($isDepot) { if ($isDepot) {
// * Dossier dépôt // * Dossier dépôt
$esMust = array_merge($esMust, [[ $esMust = array_merge($esMust, [[
@ -856,21 +883,26 @@ class MediaController extends Controller
return; return;
} }
// ? N'est pas dans le dossier dépot ou racine ?
if (!$dossier) { if (!$dossier) {
if ($request->folder === -1) { // ? Recherche globale ?
if ($request->input('folder') === -1) {
// * Recherche globale . // * Recherche globale .
$esMust = array_merge($esMust, [ $esMust = array_merge($esMust, [
// * AND
\array_undot(['bool.must.match.sujet_id' => $sujet->codeSujet]) \array_undot(['bool.must.match.sujet_id' => $sujet->codeSujet])
]); ]);
} else { } else {
// * Dossier racine . // * Dossier racine .
$esMust = array_merge($esMust, [ $esMust = array_merge($esMust, [
// * AND
\array_undot(['bool.should.match.sujet_id' => $sujet->codeSujet]) \array_undot(['bool.should.match.sujet_id' => $sujet->codeSujet])
]); ]);
$esMustNot = array_merge($esMustNot, [ $esMustNot = array_merge($esMustNot, [
\array_undot(['exists.field' => 'dossier_id']) \array_undot(['exists.field' => 'dossier_id'])
]); ]);
} //end if } //end if
// * OR
$esShould = array_merge($esShould, [ $esShould = array_merge($esShould, [
\array_undot(['match.statut' => MediaStatut::public_etendu]), \array_undot(['match.statut' => MediaStatut::public_etendu]),
\array_undot(['match.statut' => MediaStatut::public]), \array_undot(['match.statut' => MediaStatut::public]),
@ -881,6 +913,7 @@ class MediaController extends Controller
// * Dossier classic . // * Dossier classic .
$esMust = array_merge($esMust, [[ $esMust = array_merge($esMust, [[
// * AND
\array_undot([ \array_undot([
'bool.must' => [ 'bool.must' => [
\array_undot(['match.sujet_id' => $sujet->codeSujet]), \array_undot(['match.sujet_id' => $sujet->codeSujet]),
@ -889,9 +922,13 @@ class MediaController extends Controller
]) ])
]]); ]]);
// ? User n'est pas ADMIN ?
if (!$user->hasRole(config('roles.const.ADMIN'))) { if (!$user->hasRole(config('roles.const.ADMIN'))) {
$esFilters = array_merge($esFilters, [ // * Ajout de restrictions
// * Tout ce qui nous appartient et tout ce qui n'est pas brouillon
$esMust = array_merge($esMust, [
\array_undot([ \array_undot([
// * OR
'bool.should' => [ 'bool.should' => [
\array_undot([ \array_undot([
'bool.must_not' => [[ 'bool.must_not' => [[

View file

@ -11,6 +11,8 @@ use Illuminate\Support\Str;
use App\Models\Panier; use App\Models\Panier;
use App\Models\Format; use App\Models\Format;
use App\Models\Media; use App\Models\Media;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
class PanierController extends Controller class PanierController extends Controller
{ {
@ -19,15 +21,16 @@ class PanierController extends Controller
/** /**
* Page principale des paniers * Page principale des paniers
* *
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory * @return \Illuminate\Contracts\View\View
*/ */
public function index() public function index(): View
{ {
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = \auth()->user(); $user = \auth()->user();
// ! Has to flush Media cache before querying basket with media list
/** @var \Illuminate\Database\Eloquent\Collection $paniers */ Media::flushQueryCache();
$paniers = $user->paniersOwner; $paniers = $user->paniersOwner;
return view('panier.index')->with([ return view('panier.index')->with([
'paniers' => $paniers, 'paniers' => $paniers,
]); ]);
@ -39,12 +42,12 @@ class PanierController extends Controller
* *
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function getBaskets() public function getBaskets(): JsonResponse
{ {
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = \auth()->user(); $user = \auth()->user();
// ! Has to flush Media cache before querying basket with media list
/** @var \Illuminate\Database\Eloquent\Collection $paniers */ Media::flushQueryCache();
$paniers = $user->paniersOwner; $paniers = $user->paniersOwner;
return response()->json($paniers); return response()->json($paniers);
@ -56,18 +59,22 @@ class PanierController extends Controller
* @param \App\Http\Requests\Bo\Ajax\AddMediasBasketRequest $request * @param \App\Http\Requests\Bo\Ajax\AddMediasBasketRequest $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function addMediasBasket(AddMediasBasketRequest $request) public function addMediasBasket(AddMediasBasketRequest $request): JsonResponse
{ {
/** @var \App\Models\Panier $panier */ /** @var \App\Models\Panier $panier */
$panier = Panier::whereId($request->panier_id) $panier = Panier::query()
->with('mediaList')->firstOrFail(); ->where('id', $request->input('panier_id'))
->with('mediaList')
->firstOrFail();
// * Sync every media to basket // * Sync every media to basket
$panier->mediaList()->sync(array_merge( $panier->mediaList()->sync(array_merge(
$panier->mediaList()->pluck('id')->all(), $panier->mediaList()->pluck('id')->all(),
$request->mediaList $request->input('mediaList')
)); ));
Media::flushQueryCache();
return response()->json(); return response()->json();
} }
@ -77,15 +84,18 @@ class PanierController extends Controller
* @param \App\Http\Requests\Bo\Ajax\RemoveMediasBasketRequest $request * @param \App\Http\Requests\Bo\Ajax\RemoveMediasBasketRequest $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function removeMediasBasket(RemoveMediasBasketRequest $request) public function removeMediasBasket(RemoveMediasBasketRequest $request): JsonResponse
{ {
/** @var \App\Models\Panier $panier */ /** @var \App\Models\Panier $panier */
$panier = Panier::whereId($request->panier_id) $panier = Panier::query()
->with('mediaList')->firstOrFail(); ->where('id', $request->input('panier_id'))
->with('mediaList')
->firstOrFail();
/** @var \App\Models\Media $media */ /** @var \App\Models\Media $media */
$media = Media::whereId($request->media_id)->firstOrFail(); $media = Media::query()
->where('id', $request->input('media_id'))
->firstOrFail();
$panier->mediaList()->detach($media); $panier->mediaList()->detach($media);
@ -98,13 +108,13 @@ class PanierController extends Controller
* @param \App\Http\Requests\Bo\Ajax\CreateBasketRequest $request * @param \App\Http\Requests\Bo\Ajax\CreateBasketRequest $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function createBasket(CreateBasketRequest $request) public function createBasket(CreateBasketRequest $request): JsonResponse
{ {
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
$panier = new Panier(); $panier = new Panier();
$panier->libelle = $request->title; $panier->libelle = $request->input('title');
$panier->uid = Str::uuid(); $panier->uid = Str::uuid();
$panier->owner()->associate($user); $panier->owner()->associate($user);
$panier->saveOrFail(); $panier->saveOrFail();
@ -118,10 +128,12 @@ class PanierController extends Controller
* @param \App\Http\Requests\Bo\Ajax\DestroyBasketRequest $request * @param \App\Http\Requests\Bo\Ajax\DestroyBasketRequest $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function destroyBasket(DestroyBasketRequest $request) public function destroyBasket(DestroyBasketRequest $request): JsonResponse
{ {
/** @var \App\Models\Panier $basket */ /** @var \App\Models\Panier $basket */
$basket = Panier::whereId($request->basket_id)->firstOrFail(); $basket = Panier::query()
->where('id', $request->input('basket_id'))
->firstOrFail();
$basket->deleteOrFail(); $basket->deleteOrFail();
@ -134,9 +146,9 @@ class PanierController extends Controller
* Page publique d'un panier * Page publique d'un panier
* *
* @param \App\Models\Panier $panier * @param \App\Models\Panier $panier
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory * @return \Illuminate\Contracts\View\View
*/ */
public function showBasket(Panier $panier) public function showBasket(Panier $panier): View
{ {
/** @var \App\Models\User|null $user */ /** @var \App\Models\User|null $user */
$user = auth()->user(); $user = auth()->user();
@ -150,9 +162,12 @@ class PanierController extends Controller
} }
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Format> $formats */ /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Format> $formats */
$formats = Format::withoutGlobalScope('App\Scopes\SystemScope') $formats = Format::query()
->where('system', true)->get(); ->withoutGlobalScope('App\Scopes\SystemScope')
return view('panier.show')->with([ ->where('system', true)
->get();
return view('panier.show', [
'panier' => $panier, 'panier' => $panier,
'formats' => $formats, 'formats' => $formats,
]); ]);
@ -164,10 +179,12 @@ class PanierController extends Controller
* @param \App\Http\Requests\Bo\Ajax\SaveBasketPropsRequest $request * @param \App\Http\Requests\Bo\Ajax\SaveBasketPropsRequest $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function saveBasketProperty(SaveBasketPropsRequest $request) public function saveBasketProperty(SaveBasketPropsRequest $request): JsonResponse
{ {
/** @var \App\Models\Panier $panier */ /** @var \App\Models\Panier $panier */
$panier = Panier::whereId($request->basket_id)->firstOrFail(); $panier = Panier::query()
->where('id', $request->input('basket_id'))
->firstOrFail();
$panier->fill($request->validated()); $panier->fill($request->validated());
$panier->saveOrFail(); $panier->saveOrFail();

View file

@ -15,6 +15,7 @@ use App\Models\Sujet;
use App\Models\TypeMedia; use App\Models\TypeMedia;
use App\Models\User; use App\Models\User;
use App\Traits\Http\HandlesMedia; use App\Traits\Http\HandlesMedia;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile; use Illuminate\Http\UploadedFile;
@ -97,7 +98,7 @@ class UploadController extends Controller
// 400 instead of 422 is for resumablejs to handle properly. // 400 instead of 422 is for resumablejs to handle properly.
return \response()->json($e->errors(), 400); return \response()->json($e->errors(), 400);
} }
}//end if } //end if
// We are in chunk mode, lets send the current progress. // We are in chunk mode, lets send the current progress.
/** @var AbstractHandler $handler */ /** @var AbstractHandler $handler */
@ -143,12 +144,11 @@ class UploadController extends Controller
$this->validateUploadedFile($uplodedFile); $this->validateUploadedFile($uplodedFile);
/** @var \App\Models\Media */ /** @var \App\Models\Media */
$media = Media::whereId($request->media_id) $media = Media::query()
->whereHas('sujet', function ($q) use ($sujet) { ->where('id', $request->input('media_id'))
$q->whereId($sujet->id); ->whereHas('sujet', fn(Builder $q) => $q->where('codeSujet', $sujet->codeSujet))
})->whereHas('dossier', function ($q) use ($dossier) { ->whereHas('dossier', fn(Builder $q) => $q->where('id', $dossier->id))
$q->whereId($dossier->id); ->firstOrNew();
})->firstOrNew();
// Save the file and return any response you need. // Save the file and return any response you need.
return $this->createOrUpdateMedia($user, $uplodedFile, $media, $dossier, $sujet); return $this->createOrUpdateMedia($user, $uplodedFile, $media, $dossier, $sujet);
@ -156,7 +156,7 @@ class UploadController extends Controller
// 400 instead of 422 is for resumablejs to handle properly. // 400 instead of 422 is for resumablejs to handle properly.
return \response()->json($e->errors(), 400); return \response()->json($e->errors(), 400);
} }
}//end if } //end if
// We are in chunk mode, lets send the current progress. // We are in chunk mode, lets send the current progress.
/** @var AbstractHandler $handler */ /** @var AbstractHandler $handler */
@ -214,7 +214,7 @@ class UploadController extends Controller
'File guessed extensions :guessedExts does not match file name extension :extension', 'File guessed extensions :guessedExts does not match file name extension :extension',
[ [
'guessedExt' => $guessedExts, 'guessedExt' => $guessedExts,
'extension' => $mediaExtension, 'extension' => $mediaExtension->value,
] ]
) )
]); ]);
@ -341,6 +341,8 @@ class UploadController extends Controller
$media->saveOrFail(); $media->saveOrFail();
Media::flushQueryCache();
// * Get props inserted by DB. // * Get props inserted by DB.
return response()->json($media->refresh()); return response()->json($media->refresh());
}); });

View file

@ -190,10 +190,14 @@ class UserController extends Controller
$marques = Marque::orderBy('libMarq', 'asc')->get(); $marques = Marque::orderBy('libMarq', 'asc')->get();
$userSujets = $user->sujets; $userSujets = $user->sujets;
$sujets = Sujet::where('sujet_dam', true)->orderBy('libelle', 'asc')->get(); $sujets = Sujet::where('sujet_dam', true)->orderBy('libelle', 'asc')->get();
$users = User::select(['id', 'email'])->whereIn('role', [ $users = User::select(['id', 'email'])
->whereIn('role', [
config('roles.const.ADMIN'), config('roles.const.CONTRIBUTEUR'), config('roles.const.ADMIN'), config('roles.const.CONTRIBUTEUR'),
config('roles.const.REDACTEUR') config('roles.const.REDACTEUR')
])->where('id', '!=', $user->id)->get(); ])
->where('id', '!=', $user->id)
->orderBy('email')
->get();
return view('users.edit')->with([ return view('users.edit')->with([
'user' => $user, 'roles' => $roles, 'users' => $users, 'user' => $user, 'roles' => $roles, 'users' => $users,
'userMarques' => $userMarques, 'marques' => $marques, 'userMarques' => $userMarques, 'marques' => $marques,

View file

@ -39,7 +39,9 @@ class XmlArcadiaMediasIn extends XmlJobs
* *
* @var array * @var array
*/ */
protected $nullableFields = []; protected $nullableFields = [
'version'
];
/** /**
* Fields that are unique * Fields that are unique
@ -69,7 +71,7 @@ class XmlArcadiaMediasIn extends XmlJobs
$media = Media::withTrashed()->where($uniqueColumnsKey)->firstOrFail(); $media = Media::withTrashed()->where($uniqueColumnsKey)->firstOrFail();
$media->arcadia_id = $line['arcadia_id']; $media->arcadia_id = $line['arcadia_id'];
$media->version = $line['version']; $media->version = $line['version'] ?? 1;
$media->isLocked = false; $media->isLocked = false;
$media->saveOrFail(); $media->saveOrFail();

View file

@ -132,7 +132,7 @@ class ArcadiaLinkUtilities
$storage->path($filename), $storage->path($filename),
\ZipArchive::CREATE | \ZipArchive::OVERWRITE \ZipArchive::CREATE | \ZipArchive::OVERWRITE
); );
$success = $zip->addFromString($xml, 'media.xml') && $success; $success = $zip->addFromString('media.xml', $xml) && $success;
$success = $zip->addFile($media->full_path, $media->basename) && $success; $success = $zip->addFile($media->full_path, $media->basename) && $success;
$success = $zip->close() && $success; $success = $zip->close() && $success;
unset($zip); unset($zip);
@ -245,7 +245,7 @@ class ArcadiaLinkUtilities
->appendChild($dom->createCDATASection($formatModel['hauteur'])); ->appendChild($dom->createCDATASection($formatModel['hauteur']));
$format->appendChild($dom->createElement('lien')) $format->appendChild($dom->createElement('lien'))
->appendChild($dom->createCDATASection(\sprintf( ->appendChild($dom->createCDATASection(\sprintf(
"%s/{$media->folder}{$media->uid}_%s.{$media->extension->value}", "%s/{$media->folder}/{$media->uid}_%s.{$media->extension->value}",
config('app.url'), config('app.url'),
$formatModel['libelle'] $formatModel['libelle']
))); )));

View file

@ -5,6 +5,13 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon; use Carbon\Carbon;
/**
* @property integer $arcadia_id The ID on Arcadia side, Defaults to 0 (not linked).
* @property string $filename
*
* @property-read \App\Models\Media $media Media BelongsTo relationship.
* @package App\Models
*/
class ArcadiaLink extends Model class ArcadiaLink extends Model
{ {
// * GETTERS // * GETTERS

View file

@ -75,6 +75,6 @@ class Article extends Model
*/ */
public function mediaList() public function mediaList()
{ {
return $this->belongsToMany(Media::class, 'media_article', 'media_id', 'article_id'); return $this->belongsToMany(Media::class, 'media_article', 'article_id', 'media_id');
} }
} }

View file

@ -4,6 +4,7 @@ namespace App\Models;
use App\Enums\MediaStatut; use App\Enums\MediaStatut;
use App\Models\User; use App\Models\User;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -73,19 +74,24 @@ class Dossier extends Model
/** @var \App\Model\User $user */ /** @var \App\Model\User $user */
$user = Auth::user(); $user = Auth::user();
// * dossier classic // ? Est un dossier dépot ou racine ?
if ($this->parent_id != 1 && $this->id != 1) { if ($this->parent_id === 1 or $this->id === 1) {
// * Dossier dépôt
return $this->mediaList()->count();
}
// * Dossier classic
// ? User is admin ?
if ($user->hasRole(config('roles.const.ADMIN'))) { if ($user->hasRole(config('roles.const.ADMIN'))) {
// * Tout de tout le monde
return $this->mediaList()->count(); return $this->mediaList()->count();
} else { }
// * Tous les non brouillons ou crées par le user
return $this->mediaList() return $this->mediaList()
->where('statut', '<>', MediaStatut::brouillon) ->where(fn (Builder $q) => $q->where('statut', '!=', MediaStatut::brouillon)
->orWhere('created_by', $user->id)->count(); ->orWhere('created_by', $user->id))
} ->count();
} else {
// * dossier dépôt
return $this->mediaList()->count();
}
} }
// * RELATIONSHIPS // * RELATIONSHIPS
@ -120,7 +126,7 @@ class Dossier extends Model
*/ */
public function mediaList() public function mediaList()
{ {
return $this->hasMany(Media::class, 'dossier_id', 'id'); return $this->hasMany(Media::class);
} }
/** /**

View file

@ -48,4 +48,24 @@ class Historique extends Model
{ {
return $this->belongsTo(Media::class); return $this->belongsTo(Media::class);
} }
// * METHODS
/**
* Get the instance as an array.
*
* @return array<TKey,TValue>
*/
public function toArray(): array
{
return \array_merge(
parent::toArray(),
[
'type' => [
'value' => $this->type,
'label' => $this->type->label()
]
]
);
}
} }

View file

@ -39,14 +39,27 @@ class Media extends Model
*/ */
public $cacheDriver = 'redis'; public $cacheDriver = 'redis';
/**
* Is the model a duplicate of another (only true before we save it in database)
*
* @var boolean
*/
public $isDuplicate = false;
/** /**
* The relations to eager load on every query. * The relations to eager load on every query.
* *
* @var array * @var array
*/ */
protected $with = [ protected $with = [
'owner', 'tags', 'etiquette', 'articles', 'sujet', 'owner',
'typeMedia', 'societes', 'marques' 'tags',
'etiquette',
'articles',
'sujet',
'typeMedia',
'societes',
'marques'
]; ];
/** /**
@ -209,8 +222,10 @@ class Media extends Model
$user = auth()->user(); $user = auth()->user();
MediaCreated::dispatch($user, $model); MediaCreated::dispatch($user, $model);
if (empty($model->isDuplicate)) {
/** @throws \RuntimeException */ /** @throws \RuntimeException */
$model->addToElasticSearch(); $model->addToElasticSearch();
}
}); });
static::updating(function (self $model) { static::updating(function (self $model) {
if ($model->statut === MediaStatut::brouillon and $model->arcadia_id) { if ($model->statut === MediaStatut::brouillon and $model->arcadia_id) {
@ -226,8 +241,8 @@ class Media extends Model
/** @var \App\Models\User */ /** @var \App\Models\User */
$user = auth()->user(); $user = auth()->user();
// * Prevent soft delete trigerring update event // * If update is not running from console, we prevent soft delete before trigerring update event
if (!\array_key_exists('deleted_at', $model->getChanges())) { if ($user and !\array_key_exists('deleted_at', $model->getChanges())) {
MediaUpdated::dispatch($user, $model); MediaUpdated::dispatch($user, $model);
} }
@ -252,13 +267,21 @@ class Media extends Model
/** @throws \RuntimeException */ /** @throws \RuntimeException */
$model->removeFromElasticSearch(); $model->removeFromElasticSearch();
$model->deleteFilesOnAllPath();
}); });
} }
// * Laravel Behaviors // * Laravel Behaviors
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName()
{
return 'uid';
}
/** /**
* Set the base cache tags that will be present * Set the base cache tags that will be present
* on all queries. * on all queries.
@ -457,7 +480,7 @@ class Media extends Model
*/ */
public function paniers() public function paniers()
{ {
return $this->belongsToMany(Panier::class); return $this->belongsToMany(Panier::class, 'panier_media');
} }
// * METHODS // * METHODS
@ -782,7 +805,7 @@ class Media extends Model
$storage = Storage::disk('media'); $storage = Storage::disk('media');
// * format spécifique // * format spécifique
if ($format->system) { if (!$format->system) {
if (in_array($this->extension, ['gif', 'jpeg', 'jpg', 'png', 'pdf', 'ai', 'psd'])) { if (in_array($this->extension, ['gif', 'jpeg', 'jpg', 'png', 'pdf', 'ai', 'psd'])) {
return $storage->path("/{$this->folder}/{$this->uid}_{$format->libelle}.{$format->extension->value}"); return $storage->path("/{$this->folder}/{$this->uid}_{$format->libelle}.{$format->extension->value}");
} }
@ -797,7 +820,7 @@ class Media extends Model
} elseif (in_array($this->extension, ['pdf', 'ai', 'psd'])) { } elseif (in_array($this->extension, ['pdf', 'ai', 'psd'])) {
return $storage->path("/{$this->folder}/{$this->uid}_{$format->libelle}.png"); return $storage->path("/{$this->folder}/{$this->uid}_{$format->libelle}.png");
} }
return $storage->path("/{$this->folder}/{$this->uid}.{$this->extension}"); return $storage->path("/{$this->folder}/{$this->uid}.{$this->extension->value}");
} }
throw new \RuntimeException("Unhandled Format $format->id $format->libelle"); throw new \RuntimeException("Unhandled Format $format->id $format->libelle");
} }

View file

@ -6,6 +6,36 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
/**
* @property string $firstname Prénom.
* @property string $lastname Nom.
* @property string $email Email.
* @property string $objectguid
* @property string $matricule Unique LDAP.
* @property-read \Illuminate\Support\Carbon $email_verified_at Mail verified at date.
* @property string $password Mot de passe.
* @property string $remember_token
* @property integer $role Rôle in config/role; 1 => Admin.
* @property-read \Illuminate\Support\Carbon $created_at Created date.
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
*
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Marque> $marques
* Marques BelongsToMany relationship.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Dossier> $dossiers
* Dossiers BelongsToMany relationship.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Sujet> $sujets
* Sujets BelongsToMany relationship.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Media> $mediaList
* Medias HasMany relationship.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Historique> $historiques
* Historiques HasMany relationship.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Recherche> $recherches
* Recherches HasMany relationship.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Panier> $paniersOwner
* Paniers HasMany relationship that belongs to the user.
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Panier> $paniersFavoris
* Paniers HasMany relationship.
*/
class User extends Authenticatable class User extends Authenticatable
{ {
use HasFactory; use HasFactory;

View file

@ -2,9 +2,9 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
@ -17,6 +17,12 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
if (
in_array(config('app.env'), ['local', 'testing']) && config('app.bypassldap') && !app()->runningInConsole()
) {
Auth::loginUsingId(24);
}
// !!! Fuc**** Lab LDC exception OMG !!! // !!! Fuc**** Lab LDC exception OMG !!!
if (!in_array(config('app.env'), ['local', 'testing'])) { if (!in_array(config('app.env'), ['local', 'testing'])) {
URL::forceRootUrl(config('app.url')); URL::forceRootUrl(config('app.url'));
@ -26,11 +32,10 @@ class AppServiceProvider extends ServiceProvider
return $url->current(); return $url->current();
}); });
} }
// * LOCAL HTTPS FIX // * Force HTTPS
if (!in_array(config('app.env'), ['local', 'testing'])) {
URL::forceScheme('https'); URL::forceScheme('https');
}
// * HA PROXY FIX // * REVERSE PROXY FIX
App::singleton('clientIp', function () { App::singleton('clientIp', function () {
if (config('app.env') == 'local') { if (config('app.env') == 'local') {
return request()->getClientIp(); return request()->getClientIp();
@ -38,6 +43,7 @@ class AppServiceProvider extends ServiceProvider
return request()->server('HTTP_X_FORWARDED_FOR') ?? request()->getClientIp(); return request()->server('HTTP_X_FORWARDED_FOR') ?? request()->getClientIp();
} }
}); });
// * LOCAL FORCE eg: for Carbon // * LOCAL FORCE eg: for Carbon
foreach ([\LC_TIME, \LC_MESSAGES, \LC_COLLATE, \LC_CTYPE, \LC_MONETARY] as $category) { foreach ([\LC_TIME, \LC_MESSAGES, \LC_COLLATE, \LC_CTYPE, \LC_MONETARY] as $category) {
setlocale( setlocale(
@ -47,9 +53,5 @@ class AppServiceProvider extends ServiceProvider
); );
} }
Carbon::setLocale(config('app.locale')); Carbon::setLocale(config('app.locale'));
if (!app()->runningInConsole()) {
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
Paginator::useBootstrap();
}//end if
} }
} }

View file

@ -41,9 +41,6 @@ class RouteServiceProvider extends ServiceProvider
->group(base_path('routes/api.php')); ->group(base_path('routes/api.php'));
}); });
Route::bind('media', function ($value) {
return Media::whereUid($value)->firstOrFail();
});
Route::bind('basket_uuid', function ($value) { Route::bind('basket_uuid', function ($value) {
return Panier::where('uid', $value) return Panier::where('uid', $value)
->with('owner')->firstOrFail(); ->with('owner')->firstOrFail();

View file

@ -0,0 +1,34 @@
<?php
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
$appInfos = Cache::remember('composer', 360, function () {
return json_decode(File::get(\app_path('../composer.json')));
});
// Share composer.json infos.
if (isset($appInfos->name) and isset($appInfos->version)) {
View::share('cpsr_name', $appInfos->name);
View::share('cpsr_version', $appInfos->version);
}
if (!app()->runningInConsole()) {
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
Paginator::useBootstrap();
}
}
}

View file

@ -23,7 +23,6 @@
"laravel/tinker": "^2.7", "laravel/tinker": "^2.7",
"laravel/ui": "^3.0", "laravel/ui": "^3.0",
"laravelcollective/html": "^6.3", "laravelcollective/html": "^6.3",
"ldc/web-status-checker-laravel": "^1.0",
"mews/purifier": "^3.3", "mews/purifier": "^3.3",
"pion/laravel-chunk-upload": "^1.5", "pion/laravel-chunk-upload": "^1.5",
"rennokki/laravel-eloquent-query-cache": "^3.3" "rennokki/laravel-eloquent-query-cache": "^3.3"
@ -97,11 +96,5 @@
} }
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true
"repositories": [
{
"type": "composer",
"url": "https://lab.s-web.fr/api/v4/group/23/-/packages/composer/packages.json"
}
]
} }

2281
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,8 @@ use Illuminate\Support\Facades\Facade;
return [ return [
'bypassldap' => env('BYPASS_LDAP', false),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Name | Application Name
@ -178,7 +180,8 @@ return [
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class, App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class App\Providers\RouteServiceProvider::class,
App\Providers\ViewServiceProvider::class
], ],

View file

@ -12,6 +12,6 @@ return [
* so you can receive email if things go mad * so you can receive email if things go mad
*/ */
'contactsList' => [ 'contactsList' => [
env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr') env('MAIL_LIST_SERVICEWEB', 'digital@ldc.fr')
] ]
]; ];

View file

@ -117,8 +117,9 @@ return [
// * Contacts List // * Contacts List
'contactsList' => [ 'contactsList' => [
'invalidXml' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_LIST_INVALID_XML', 'equipe.web@ldc.fr')), 'invalidXml' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_LIST_INVALID_XML', 'digital@ldc.fr')),
'serviceweb' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')) 'serviceweb' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_LIST_SERVICEWEB', 'digital@ldc.fr')),
'admin' => explode(',', env('MAIL_ADMIN')),
], ],
]; ];

View file

@ -1,5 +1,6 @@
<?php <?php
// TODO: Pass this as an enum.
return [ return [
'const' => [ 'const' => [
'ADMIN' => '1', 'ADMIN' => '1',

View file

@ -0,0 +1,48 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$linkedMediaIdList = DB::table('arcadia_links')->pluck('media_id');
$existingMediaIdList = DB::table('media')->whereIn('id', $linkedMediaIdList)->pluck('id');
$linkIdListToRemove = $linkedMediaIdList->filter(fn (int $media_id) =>
!$existingMediaIdList->contains($media_id));
// * Remove Orphan links
DB::transaction(fn () => DB::table('arcadia_links')->whereIn('media_id', $linkIdListToRemove)->delete());
// * Add foreign Key
Schema::table('arcadia_links', function (Blueprint $table) {
$table->unsignedBigInteger('media_id')->nullable(false)->default(null)->change();
});
Schema::table('arcadia_links', function (Blueprint $table) {
$table->foreign('media_id')->references('id')->on('media');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('arcadia_links', function (Blueprint $table) {
$table->dropForeign(['media_id']);
});
Schema::table('arcadia_links', function (Blueprint $table) {
$table->bigInteger('media_id')->default(0)->change();
});
}
};

View file

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- < XSD deviné, basé sur la BDD et cette seule affirmation "les 3 champs sont obligatoires" @author Jérémy Munsch jeremy.munsch@ldc.fr > -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="MEDIA_VISUEL"> <xs:element name="MEDIA_VISUEL">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element name="codeArcadia" type="_positive_unsigned_integer_without_leading_zeros" /> <xs:element name="codeArcadia" type="_positive_unsigned_integer_without_leading_zeros" />
<xs:element name="code_DAM" type="_positive_unsigned_integer_without_leading_zeros"/> <xs:element name="code_DAM" type="_positive_unsigned_integer_without_leading_zeros"/>
<xs:element name="version" type="_positive_unsigned_integer_without_leading_zeros"/> <xs:element name="version" minOccurs="1" nillable="true" >
<xs:simpleType>
<xs:union memberTypes="_positive_unsigned_integer_without_leading_zeros xs:string"/>
</xs:simpleType>
</xs:element>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@ -16,5 +18,4 @@
<xs:pattern value="[123456789]\d*"/> <xs:pattern value="[123456789]\d*"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:schema> </xs:schema>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- < XSD deviné, basé sur la BDD et cette seule affirmation "les 3 champs sont obligatoires" @author Jérémy Munsch jeremy.munsch@ldc.fr > -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="MEDIA_VISUEL">
<xs:complexType>
<xs:sequence>
<xs:element name="codeArcadia" type="_positive_unsigned_integer_without_leading_zeros" />
<xs:element name="code_DAM" type="_positive_unsigned_integer_without_leading_zeros"/>
<xs:element name="version" type="_positive_unsigned_integer_without_leading_zeros"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="_positive_unsigned_integer_without_leading_zeros">
<xs:restriction base="xs:positiveInteger">
<xs:pattern value="[123456789]\d*"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

View file

@ -163,8 +163,8 @@
</template> </template>
<script> <script>
import Resumable from "resumablejs";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import Resumable from "resumablejs";
export default { export default {
name: "MmActionsComponent", name: "MmActionsComponent",
@ -224,7 +224,7 @@ export default {
} else { } else {
this.$loading.show({ delay: 0 }); this.$loading.show({ delay: 0 });
axios axios
.post(`/ajax/media/${this.storeGrabbed[0].id}/duplicate`) .post(`/ajax/media/${this.storeGrabbed[0].uid}/duplicate`)
.then((response) => { .then((response) => {
this.$loading.hide(); this.$loading.hide();
if (response.data.status === true) { if (response.data.status === true) {

View file

@ -167,6 +167,7 @@ export default {
}, },
mounted() { mounted() {
this.resetInfiniteScroll(); this.resetInfiniteScroll();
this.init();
}, },
data: function () { data: function () {
return { return {
@ -221,6 +222,10 @@ export default {
type: "updateGrabbed", type: "updateGrabbed",
grabbed: [], grabbed: [],
}); });
this.$store.commit({
type: "updateFolder",
folder: this.storeFolder,
});
this.loadMediaList(); this.loadMediaList();
//set dateSorted //set dateSorted
this.dateSorted = false; this.dateSorted = false;

View file

@ -126,6 +126,7 @@ export default {
components: { FontAwesomeIcon }, components: { FontAwesomeIcon },
mounted() { mounted() {
const data = JSON.parse(this.$parent.$options.json); const data = JSON.parse(this.$parent.$options.json);
this.selectedFolder = data.selectedFolder;
this.textsearch = data.textsearch ? String(data.textsearch) : ""; this.textsearch = data.textsearch ? String(data.textsearch) : "";
this.oTypesmedia = data.typesmedia; this.oTypesmedia = data.typesmedia;
this.oEtiquettes = data.etiquettes; this.oEtiquettes = data.etiquettes;
@ -152,6 +153,7 @@ export default {
sReferentiel: [], sReferentiel: [],
sTexte: "", sTexte: "",
initText: 0, initText: 0,
selectedFolder: {},
}; };
}, },
watch: { watch: {
@ -304,15 +306,22 @@ export default {
} }
}, },
reset() { reset() {
this.resetFolder();
this.sTypevue = []; this.sTypevue = [];
this.sTypemedias = []; this.sTypemedias = [];
this.sEtiquettes = []; this.sEtiquettes = [];
this.sReferentiel = []; this.sReferentiel = [];
this.sTexte = ""; this.sTexte = "";
const filters = this.selectedFolder ? [{
type: "dossier_id",
legend: "Dossier : ",
value: this.selectedFolder.id,
libelle: this.selectedFolder.libelle,
}] : [];
this.resetFolder();
this.selectedFolder = null;
this.$store.commit({ this.$store.commit({
type: "updateFilters", type: "updateFilters",
filters: [], filters: filters,
}); });
if (this.textsearch.length && this.initText === 0) { if (this.textsearch.length && this.initText === 0) {
this.addText(this.textsearch); this.addText(this.textsearch);

View file

@ -182,9 +182,25 @@ export default {
return this.$store.state.reload; return this.$store.state.reload;
}, },
}, },
mounted() {
const data = JSON.parse(this.$parent.$options.json);
if (data.selectedFolder && data.selectedFolder != -1) {
this.selectedFolder = data.selectedFolder;
this.selectedSubject = data.selectedSubject;
this.$store.commit({
type: "updateFolder",
folder: data.selectedFolder.id ?? -1,
});
this.storeFolder = data.selectedFolder.id;
this.$nextTick(() => {
this.initFolders(this.selectedFolder, this.selectedSubject);
})
}
},
data() { data() {
return { return {
selectedFolder: false, selectedFolder: false,
selectedSubject: false,
isLoading: true, isLoading: true,
oFolders: [], oFolders: [],
racineCount: 0, racineCount: 0,
@ -194,6 +210,7 @@ export default {
watch: { watch: {
storeSujet() { storeSujet() {
this.initFolders(); this.initFolders();
this.selectedFolder = null;
}, },
storeReload() { storeReload() {
this.reload(); this.reload();
@ -224,7 +241,7 @@ export default {
}); });
} }
}, },
initFolders(toSelectFolder = false) { initFolders(toSelectFolder = false, selectedSubject = false) {
const self = this; const self = this;
self.isLoading = true; self.isLoading = true;
self.folders = []; self.folders = [];
@ -232,7 +249,7 @@ export default {
axios axios
.get("/ajax/load-folders", { .get("/ajax/load-folders", {
params: { params: {
sujet_id: self.storeSujet, sujet_id: selectedSubject ? selectedSubject : self.storeSujet,
}, },
}) })
.then((response) => { .then((response) => {

View file

@ -100,12 +100,12 @@
<script> <script>
// ResumableJs // ResumableJs
import Resumable from "resumablejs";
import MePreviewComponent from "./tabs/MePreviewComponent.vue";
import MeEditComponent from "./tabs/MeEditComponent.vue";
import MeLinksComponent from "./tabs/MeLinksComponent.vue";
import MeHistoryComponent from "./tabs/MeHistoryComponent.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import Resumable from "resumablejs";
import MeEditComponent from "./tabs/MeEditComponent.vue";
import MeHistoryComponent from "./tabs/MeHistoryComponent.vue";
import MeLinksComponent from "./tabs/MeLinksComponent.vue";
import MePreviewComponent from "./tabs/MePreviewComponent.vue";
export default { export default {
name: "MmEditComponent", name: "MmEditComponent",
@ -180,7 +180,7 @@ export default {
var query = { var query = {
sujet_id: this.storeMedia.sujet_id, sujet_id: this.storeMedia.sujet_id,
dossier_id: this.storeMedia.dossier_id, dossier_id: this.storeMedia.dossier_id,
replaceMediaId: this.storeMedia.id, media_id: this.storeMedia.id,
}; };
this.r.updateQuery(query); this.r.updateQuery(query);
} else { } else {
@ -292,7 +292,7 @@ export default {
}, },
SaveMedia() { SaveMedia() {
axios axios
.put(`/ajax/media/${this.storeMedia.id}`, { .put(`/ajax/media/${this.storeMedia.uid}`, {
media: this.storeMedia, media: this.storeMedia,
}) })
.then((response) => { .then((response) => {

View file

@ -93,7 +93,7 @@
<option :value="null" selected disabled> <option :value="null" selected disabled>
Sélectionnez un type de variante Sélectionnez un type de variante
</option> </option>
<option v-for="item in storeTypesvariante" :value="item.codeVariante"> <option v-for="item in availableVariantes" :value="item.codeVariante">
{{ item.libelle }} {{ item.libelle }}
</option> </option>
</select> </select>
@ -394,6 +394,9 @@ export default {
storeRole() { storeRole() {
return this.$store.state.role; return this.$store.state.role;
}, },
availableVariantes() {
return this.storeTypesvariante.filter(e => e.typevue_id === this.oMedia.type_vue_id);
}
}, },
watch: { watch: {
marques() { marques() {
@ -423,7 +426,6 @@ export default {
} }
}, },
searchMarques() { searchMarques() {
console.log("search");
this.refreshMarques(); this.refreshMarques();
}, },
searchSocietes() { searchSocietes() {
@ -545,9 +547,10 @@ export default {
__DAM.methods.sessionTimedOut(); __DAM.methods.sessionTimedOut();
return; return;
} }
const errorMessage = error.response.data.message ?? "Erreur lors de l'opération, merci d'actualiser la page.";
$.fancyMessage({ $.fancyMessage({
title: "Lier un média à Arcadia", title: "Lier un média à Arcadia",
message: "Erreur lors de l'opération, merci d'actualiser la page.", message: errorMessage,
type: "error", type: "error",
}); });
console.error(error); console.error(error);
@ -710,10 +713,13 @@ export default {
.then((response) => { .then((response) => {
const result = response.data; const result = response.data;
if (result.article.utilisableGroupe === 1) { if (result.article.utilisableGroupe === 1) {
const index = this.oMedia.articles.find( const index = this.oMedia.articles?.find(
(e) => e.noArt === result.article.noArt (e) => e.noArt === result.article.noArt
); );
if (!index) { if (!index) {
if (!this.oMedia.articles) {
this.$set(this.oMedia, 'articles', []);
}
this.oMedia.articles.push(result.article); this.oMedia.articles.push(result.article);
} else { } else {
$.fancyMessage({ $.fancyMessage({

View file

@ -20,7 +20,7 @@
item.user.matricule item.user.matricule
}}) }})
</td> </td>
<td>{{ item.type }}</td> <td>{{ item.type.label }}</td>
<td>{{ item.description }}</td> <td>{{ item.description }}</td>
</tr> </tr>
</tbody> </tbody>

View file

@ -8,16 +8,37 @@
line-height: inherit; line-height: inherit;
padding: 0; padding: 0;
} }
.starButton, .starButton,
.nestableFolderButton { .nestableFolderButton {
@include resetButton; @include resetButton;
cursor: pointer; cursor: pointer;
color: #fff; color: #fff;
} }
.nestableFolderButton { .nestableFolderButton {
min-width: 1rem; min-width: 1rem;
min-height: 1rem; min-height: 1rem;
} }
.d-none { .d-none {
display: none !important; display: none !important;
} }
.media-link {
padding-top: 2rem;
&-btn {
background-color: #fff;
border-radius: 3px;
color: #374957;
font-size: 1rem;
padding: 8px;
&:hover,
&:focus {
background-color: #0a6fb7;
color: #fff;
}
}
}

View file

@ -1,33 +1,45 @@
@extends('layouts.app') @extends('layouts.app')
@include('layouts.header') @include('layouts.header')
@section('content') @section('content')
<main class="user_index template_2col"> <main class="user_index template_2col">
@include('modules.param-sideMenu') @include('modules.param-sideMenu')
<div class="main_content"> <div class="main_content">
<div class="heading"> <div class="heading">
<h1>Anomalies du lien Arcadia</h1> <h1>{{ __('Anomalies du lien Arcadia') }}</h1>
</div> </div>
<table class="datatable"> <table class="datatable">
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>{{ __('ID') }}</th>
<th>Media ID (DAM ID)</th> <th>{{ __('Media ID (DAM ID)') }}</th>
<th>Arcadia ID</th> <th>{{ __('Arcadia ID') }}</th>
<th>Filename</th> <th>{{ __('Filename') }}</th>
<th>Date création ZIP</th> <th>{{ __('Date création ZIP') }}</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
@foreach ($ano as $line) @foreach ($arcadiaLinkList as $arcadiaLink)
<tr class="data_row"> <tr class="data_row">
<td>{{$line->id}}</td> <td>{{ $arcadiaLink->id }}</td>
<td>{{$line->media_id}}</td> <td>{{ $arcadiaLink->media->id }}</td>
<td>{{$line->arcadia_id}}</td> <td>{{ $arcadiaLink->arcadia_id }}</td>
<td>{{$line->filename}}</td> <td>{{ $arcadiaLink->filename }}</td>
<td>{{$line->date_f}}</td> <td>{{ $arcadiaLink->date_f }}</td>
<td><a href="/media/{{$line->media_uuid}}" target="_blank">Ouvrir la fiche média</a></td> <td>
<td><a href="{{route('arcadialinks.destroy', ['id' => $line->id])}}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette anomalie ?');"><i class="fas fa-times" style="color: red"></i></a></td> <a href="{{ route('media.show', $arcadiaLink->media) }}"
title="{{ __('Ouvrir la fiche média dans un nouvel onglet') }}" target="_blank">
{{ __('Ouvrir la fiche média') }}
</a>
</td>
<td>
<a href="{{ route('arcadialinks.destroy', $arcadiaLink) }}" title="{{ __('Supprimer le lien arcadia') }}"
onclick="return confirm('{{ __('Êtes-vous sûr de vouloir supprimer cette anomalie ?') }}');">
<i class="fas fa-times" style="color: red"></i>
</a>
</td>
</tr> </tr>
@endforeach @endforeach
</table> </table>

View file

@ -1,35 +1,40 @@
@extends('layouts.app') @extends('layouts.app')
@include('layouts.header') @include('layouts.header')
@section('content') @section('content')
<main class="home"> <main class="home">
<div class="search"> <div class="search">
<div class="container"> <div class="container">
<h1><i class="fas fa-images"></i>{{ __('Bienvenue') }}</h1> <h1><i class="fas fa-images"></i>{{ __('Bienvenue') }}</h1>
<form class="input_search" action="{{ route('media_manager') }}" method="get"> <form class="input_search" action="{{ route('media_manager') }}" method="get">
<div class="select_container"> <div class="select_container">
@if($sujets->count()) @if ($sujets->count())
<select name="s"> <select name="s">
@foreach ($sujets as $sujet) @foreach ($sujets as $sujet)
<option value="{{ $sujet->codeSujet }}" >{{ $sujet->libelle }}</option> <option value="{{ $sujet->codeSujet }}">{{ $sujet->libelle }}</option>
@endforeach @endforeach
</select> </select>
@endif @endif
</div> </div>
<input type="text" name="t" value="" autofocus placeholder="Rechercher un média..."> <input name="t" type="text" value="" autofocus placeholder="Rechercher un média...">
<input type="hidden" name="d" value="-1"> <input name="d" type="hidden" value="-1">
<button type="submit"><i class="fa fa-search"></i></button> <button type="submit"><i class="fa fa-search"></i></button>
</form> </form>
<div class="media-link">
<a class="media-link-btn" href="{{ route('media_manager') }}">
<i class="fas fa-images"></i>
{{ __('Accéder aux médias') }}
</a>
</div>
</div> </div>
</div> </div>
<div class="widget"> <div class="widget">
<div class="item"> <div class="item">
<header>{{ __('Mes dernières recherches') }}</header> <header>{{ __('Mes dernières recherches') }}</header>
<div class="content"> <div class="content">
@if($recherches->count()) @if ($recherches->count())
@foreach ($recherches as $recherche) @foreach ($recherches as $recherche)
<a href="{{ route('media_manager', ['r' => $recherche->id]) }}" ><i class="fa fa-search"></i>{{ <a href="{{ route('media_manager', ['r' => $recherche->id]) }}"><i
$recherche->sujet->libelle." - ".$recherche->libelle class="fa fa-search"></i>{{ $recherche->sujet->libelle . ' - ' . $recherche->libelle }}</a>
}}</a>
@endforeach @endforeach
@else @else
<i class="fa-brands fa-searchengin"></i>&nbsp;<span>{{ __('Aucune recherche effectuée') }}</span> <i class="fa-brands fa-searchengin"></i>&nbsp;<span>{{ __('Aucune recherche effectuée') }}</span>
@ -39,9 +44,10 @@
<div class="item"> <div class="item">
<header>{{ __('Mes dossiers favoris') }}</header> <header>{{ __('Mes dossiers favoris') }}</header>
<div class="content"> <div class="content">
@if($dossiers->count()) @if ($dossiers->count())
@foreach ($dossiers as $dossier) @foreach ($dossiers as $dossier)
<a href="{{ route('media_manager', ['d' => $dossier->id, 's' => $dossier->sujet->codeSujet]) }}" ><i class="fas fa-folder"></i> {{$dossier->sujet->libelle." - ".$dossier->libelle}}</a> <a href="{{ route('media_manager', ['d' => $dossier->id, 's' => $dossier->sujet->codeSujet]) }}"><i
class="fas fa-folder"></i> {{ $dossier->sujet->libelle . ' - ' . $dossier->libelle }}</a>
@endforeach @endforeach
@else @else
<i class="fa-solid fa-folder"></i>&nbsp;<span>{{ __('Pas de dossier en favoris') }}</span> <i class="fa-solid fa-folder"></i>&nbsp;<span>{{ __('Pas de dossier en favoris') }}</span>
@ -49,5 +55,5 @@
</div> </div>
</div> </div>
</div> </div>
</main> </main>
@endsection @endsection

View file

@ -2,7 +2,7 @@
@include('layouts.header') @include('layouts.header')
@include('layouts.media_edit') @include('layouts.media_edit')
@section('content') @section('content')
<main class="media_manager template_2col"> <main class="media_manager template_2col">
<div class="side_menu"> <div class="side_menu">
@php @php
$dataVue = [ $dataVue = [
@ -11,7 +11,13 @@
]; ];
@endphp @endphp
<div id="mm-side-header" data-json='@json($dataVue)'></div> <div id="mm-side-header" data-json='@json($dataVue)'></div>
<div id="mm-folder" data-json='{}'></div> @php
$dataVue = [
'selectedFolder' => $currentFolder,
'selectedSubject' => $currentSujet,
];
@endphp
<div id="mm-folder" data-json='@json($dataVue)'></div>
</div> </div>
<div class="main_content"> <div class="main_content">
<header> <header>
@ -41,11 +47,15 @@
<div id="mm-sorter" data-json='{}'></div> <div id="mm-sorter" data-json='{}'></div>
</div> </div>
</header> </header>
<div id="mm-display" data-json='{}'></div> @php
$dataVue = [
'selectedFolder' => $currentFolder,
];
@endphp
<div id="mm-display" data-json='@json($dataVue)'></div>
</div> </div>
<div id="mm-basket" data-json='{}'></div> <div id="mm-basket" data-json='{}'></div>
</main> </main>
@endsection @endsection
@section('scripts') @section('scripts')
<!-- TODO : Faire le tri des js ci-dessous --> <!-- TODO : Faire le tri des js ci-dessous -->

View file

@ -73,11 +73,11 @@ Route::post('/ajax/add-depot-folder', [DossierController::class, 'addDepotFolder
// * Ajax pour la gestion de l'upload de média . // * Ajax pour la gestion de l'upload de média .
Route::post('/ajax/upload-media/depot', [UploadController::class, 'uploadMediaFileIntoDepot']) Route::post('/ajax/upload-media/depot', [UploadController::class, 'uploadMediaFileIntoDepot'])
->name('media.uploadDepot'); ->name('media.uploadDepot');
Route::post('/ajax/upload-media/{sujet}/{dossier}', [UploadController::class, 'uploadMediaFile']) Route::post('/ajax/upload-media/{sujet}/{dossier}', [UploadController::class, 'uploadMediaFile'])
->name('media.upload'); ->name('media.upload');
// * Les pages Front panier public. // * Les pages Front panier public.
Route::get('/basket/{basket_uuid}', [PanierController::class, 'showBasket']); Route::get('/basket/{basket_uuid}', [PanierController::class, 'showBasket']);
Route::post('/ajax/download-media-public/{format?}', [MediaController::class, 'downloadMediaPublic']) Route::post('/ajax/download-media-public/{format?}', [MediaController::class, 'downloadMediaPublic'])
->name('downloadMediaPublic'); ->name('downloadMediaPublic');