mirror of
https://gitlab.com/TheGamecraft/c-cms.git
synced 2026-04-21 10:49:10 -04:00
Merge branch '3.2.5' into 'dev'
Update schedule editor See merge request TheGamecraft/c-cms!93
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\OCOM;
|
use App\OCOM;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use function GuzzleHttp\json_encode;
|
||||||
use function GuzzleHttp\Psr7\str;
|
use function GuzzleHttp\Psr7\str;
|
||||||
|
|
||||||
class OCOMController extends Controller
|
class OCOMController extends Controller
|
||||||
@@ -699,4 +700,30 @@ X20,\"Participer à des activités
|
|||||||
{
|
{
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function jsonList()
|
||||||
|
{
|
||||||
|
$ocoms = \App\OCOM::all();
|
||||||
|
|
||||||
|
$name = [];
|
||||||
|
|
||||||
|
foreach ($ocoms as $ocom) {
|
||||||
|
array_push($name, $ocom->ocom);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(string $ocom)
|
||||||
|
{
|
||||||
|
$foo = \App\OCOM::all()->where('ocom','=',$ocom)->first();
|
||||||
|
if($foo != null)
|
||||||
|
{
|
||||||
|
return $foo->objectif_competence;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class ScheduleEditorController extends Controller
|
|||||||
"end_time" => "20:30"
|
"end_time" => "20:30"
|
||||||
],
|
],
|
||||||
2 => [
|
2 => [
|
||||||
"name" => "Periode 1",
|
"name" => "Periode 2",
|
||||||
"begin_time" => "20:30",
|
"begin_time" => "20:30",
|
||||||
"end_time" => "21:20"
|
"end_time" => "21:20"
|
||||||
]
|
]
|
||||||
|
|||||||
6
public/css/material-dashboard.css
vendored
6
public/css/material-dashboard.css
vendored
@@ -3305,9 +3305,9 @@ fieldset:disabled a.btn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:hover {
|
.btn-secondary:hover {
|
||||||
color: #ffffff;
|
color: #ffffff !important;
|
||||||
background-color: #5a6268;
|
background-color: #5a6268 !important;
|
||||||
border-color: #545b62;
|
border-color: #545b62 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:focus,
|
.btn-secondary:focus,
|
||||||
|
|||||||
10
public/js/plugins/autocomplete.js
vendored
10
public/js/plugins/autocomplete.js
vendored
@@ -104,3 +104,13 @@ function initAutoComplete(htmlClass)
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initAutoCompleteOCOM(htmlClass)
|
||||||
|
{
|
||||||
|
$.get('/api/ocom/list?api_token='+api_token, function ( data ) {
|
||||||
|
var ocoms = JSON.parse(data);
|
||||||
|
$("."+htmlClass).each(function ( index ) {
|
||||||
|
autocomplete(document.getElementById(this.id), ocoms);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
82
public/js/plugins/schedule/editor.js
vendored
82
public/js/plugins/schedule/editor.js
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
var editorTemplate;
|
||||||
|
|
||||||
function initScheduleEditor(id, eventType)
|
function initScheduleEditor(id, eventType)
|
||||||
{
|
{
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -10,7 +12,8 @@ function initScheduleEditor(id, eventType)
|
|||||||
loadCourse(pniveau,pperiode);
|
loadCourse(pniveau,pperiode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initAutoComplete("AutoComplete");
|
initAutoComplete("AutoCompleteUser");
|
||||||
|
initAutoCompleteOCOM('AutoCompleteOCOM');
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
showNotification('error','Impossible d\'initialiser l\'éditeur d\'horaire ...','top', 'center')
|
showNotification('error','Impossible d\'initialiser l\'éditeur d\'horaire ...','top', 'center')
|
||||||
@@ -84,6 +87,7 @@ function loadEventType(date)
|
|||||||
url: '/api/schedule/editor/template/'+id+'?api_token='+api_token,
|
url: '/api/schedule/editor/template/'+id+'?api_token='+api_token,
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
var result = JSON.parse(data);
|
var result = JSON.parse(data);
|
||||||
|
editorTemplate = result;
|
||||||
initScheduleEditor("scheduleEditor",id)
|
initScheduleEditor("scheduleEditor",id)
|
||||||
$.each(result, function (i, val) {
|
$.each(result, function (i, val) {
|
||||||
if(i == "is_mandatory" || i == "use_schedule" || i == "use_weekly_msg")
|
if(i == "is_mandatory" || i == "use_schedule" || i == "use_weekly_msg")
|
||||||
@@ -159,3 +163,79 @@ function loadEventType(date)
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCourseName(niveau, periode) {
|
||||||
|
setTimeout(function(){
|
||||||
|
let val = $('#ocom_n'+niveau+'_p'+periode).val();
|
||||||
|
if(val != "")
|
||||||
|
{
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: '/api/ocom/'+val+'/name?api_token='+api_token,
|
||||||
|
success: function (data) {
|
||||||
|
if(data != null && data != "")
|
||||||
|
{
|
||||||
|
$('#name_n'+niveau+'_p'+periode).val(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
showNotification('error','Erreur impossible de charger l\'objectif de rendement ...','top', 'center')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCourseMode(mode, niveau, periode)
|
||||||
|
{
|
||||||
|
if(mode == "course")
|
||||||
|
{
|
||||||
|
$('#descContainer'+niveau+'-'+periode).addClass('d-none');
|
||||||
|
$('#isDoneContainer'+niveau+'-'+periode).removeClass('d-none');
|
||||||
|
$('#isDoneContainer'+niveau+'-'+periode).addClass('d-flex');
|
||||||
|
$('#OCOMContainer'+niveau+'-'+periode).removeClass('d-none');
|
||||||
|
$('#nameContainer'+niveau+'-'+periode).removeClass('d-none');
|
||||||
|
$('#modeSwitchC'+niveau+'-'+periode).addClass('active');
|
||||||
|
$('#modeSwitchO'+niveau+'-'+periode).removeClass('active');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#descContainer'+niveau+'-'+periode).removeClass('d-none');
|
||||||
|
$('#isDoneContainer'+niveau+'-'+periode).addClass('d-none');
|
||||||
|
$('#isDoneContainer'+niveau+'-'+periode).removeClass('d-flex');
|
||||||
|
$('#OCOMContainer'+niveau+'-'+periode).addClass('d-none');
|
||||||
|
$('#nameContainer'+niveau+'-'+periode).addClass('d-none');
|
||||||
|
$('#modeSwitchC'+niveau+'-'+periode).removeClass('active');
|
||||||
|
$('#modeSwitchO'+niveau+'-'+periode).addClass('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCourseModePeriode(mode,periode)
|
||||||
|
{
|
||||||
|
$.each(editorTemplate['schedule_model']['niveaux'], function (i, val) {
|
||||||
|
selectCourseMode(mode,i+1,periode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCourseModeNiveau(mode,niveau)
|
||||||
|
{
|
||||||
|
$.each(editorTemplate['schedule_model']['periodes'], function (i, val) {
|
||||||
|
selectCourseMode(mode,niveau,i+1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlantext(toggle,id)
|
||||||
|
{
|
||||||
|
if($('#'+toggle).is(":checked"))
|
||||||
|
{
|
||||||
|
$('#'+id).removeClass('text-warning');
|
||||||
|
$('#'+id).addClass('text-success');
|
||||||
|
$('#'+id).html('Plan de cours remis')
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#'+id).addClass('text-warning');
|
||||||
|
$('#'+id).removeClass('text-success');
|
||||||
|
$('#'+id).html('Plan de cours non remis')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,51 @@
|
|||||||
<div class="row pt-2 pb-2 border-bottom border-right">
|
<div class="row bg-light">
|
||||||
<div class="col-6 mb-1">
|
<div class="col-8 pr-0 m-auto d-flex">
|
||||||
|
<div class="pr-0 m-auto d-flex" id="isDoneContainer{{$niveau}}-{{$periode}}">
|
||||||
|
<div class="togglebutton">
|
||||||
|
<label class="m-auto">
|
||||||
|
<input type="checkbox" id="plan_n{{$niveau}}_p{{$periode}}" name="plan_n{{$niveau}}_p{{$periode}}" onchange="updatePlantext('plan_n{{$niveau}}_p{{$periode}}','planText_n{{$niveau}}_p{{$periode}}')">
|
||||||
|
<span class="toggle"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="text-warning p-1 justify-content-center" id="planText_n{{$niveau}}_p{{$periode}}">
|
||||||
|
Plan de cours non remis
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-4 text-right">
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<button id="modeSwitchC{{$niveau}}-{{$periode}}" class="btn-secondary dropdown-item active m-1" onclick="selectCourseMode('course',{{$niveau}},{{$periode}})">Mode "Cours" pour cette période</button>
|
||||||
|
<button id="modeSwitchO{{$niveau}}-{{$periode}}" class="btn-secondary dropdown-item m-1" onclick="selectCourseMode('other',{{$niveau}},{{$periode}})">Mode "Autre" pour cette période</button>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<button class="btn-secondary dropdown-item" href="#">Réinitialiser</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-content text-center">
|
||||||
|
<div class="tab-pane active" id="home">
|
||||||
|
<div class="row pt-2">
|
||||||
|
<div class="col-12 d-none" id="descContainer{{$niveau}}-{{$periode}}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="exampleFormControlTextarea1">Description de la période</label>
|
||||||
|
<textarea class="form-control" id="exampleFormControlTextarea1" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 mb-1" id="OCOMContainer{{$niveau}}-{{$periode}}">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
<input type="text" placeholder="OCOM du cours" class="form-control" />
|
<div class="autocomplete">
|
||||||
|
<input type="text" placeholder="OCOM du cours" id="ocom_n{{$niveau}}_p{{$periode}}" class="form-control AutoCompleteOCOM" aria-describedby="nameHelp" autocomplete="off" required onblur="updateCourseName('{{$niveau}}','{{$periode}}')">
|
||||||
|
</div>
|
||||||
<span class="form-control-feedback">
|
<span class="form-control-feedback">
|
||||||
<i class="material-icons">done</i>
|
<i class="material-icons">done</i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6" id="nameContainer{{$niveau}}-{{$periode}}">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
<input type="text" placeholder="Nom du cours" class="form-control" />
|
<input type="text" placeholder="Nom du cours" id="name_n{{$niveau}}_p{{$periode}}" class="form-control" required />
|
||||||
<span class="form-control-feedback">
|
<span class="form-control-feedback">
|
||||||
<i class="material-icons">clear</i>
|
<i class="material-icons">clear</i>
|
||||||
</span>
|
</span>
|
||||||
@@ -17,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-6 mb-1">
|
<div class="col-6 mb-1">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
<input type="text" placeholder="Lieu du cours" class="form-control" />
|
<input type="text" placeholder="Lieu du cours" class="form-control" required/>
|
||||||
<span class="form-control-feedback">
|
<span class="form-control-feedback">
|
||||||
<i class="material-icons">done</i>
|
<i class="material-icons">done</i>
|
||||||
</span>
|
</span>
|
||||||
@@ -26,11 +62,16 @@
|
|||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
<div class="autocomplete">
|
<div class="autocomplete">
|
||||||
<input type="text" placeholder="Nom de l'instructeur" id="instruc_n{{$niveau}}_p{{$periode}}" class="form-control AutoComplete" aria-describedby="nameHelp" autocomplete="off" required>
|
<input type="text" placeholder="Nom de l'instructeur" id="instruc_n{{$niveau}}_p{{$periode}}" class="form-control AutoCompleteUser" aria-describedby="nameHelp" autocomplete="off" required>
|
||||||
</div>
|
</div>
|
||||||
<span class="form-control-feedback">
|
<span class="form-control-feedback">
|
||||||
<i class="material-icons">done</i>
|
<i class="material-icons">done</i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="updates">
|
||||||
|
Test
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
</div>
|
</div>
|
||||||
@foreach($eventType->schedule_model['niveaux'] as $niveau)
|
@foreach($eventType->schedule_model['niveaux'] as $niveau)
|
||||||
<div class="col border-right border-bottom bg-dark text-white">
|
<div class="col border-right border-bottom bg-dark text-white">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-9">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
<input type="text" placeholder="Niveau" class="form-control text-white" value="{{$niveau['name']}}" />
|
<input type="text" placeholder="Niveau" class="form-control text-white" value="{{$niveau['name']}}" />
|
||||||
<span class="form-control-feedback">
|
<span class="form-control-feedback">
|
||||||
@@ -13,6 +15,17 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-3 text-right">
|
||||||
|
<button type="button" class="btn btn-link btn-sm dropdown-toggle dropdown-toggle-split text-white" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<button id="modeSwitchPeriodeC{{$loop->index+1}}" class="btn-secondary dropdown-item m-1" onclick="selectCourseModeNiveau('course',{{$loop->index+1}})">Mode "Cours" pour toutes les périodes</button>
|
||||||
|
<button id="modeSwitchPeriodeO{{$loop->index+1}}" class="btn-secondary dropdown-item m-1" onclick="selectCourseModeNiveau('other',{{$loop->index+1}})">Mode "Autre" pour toutes les période</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
<div class="col-1">
|
<div class="col-1">
|
||||||
<button class="btn btn-primary btn-fab btn-fab-mini btn-round">
|
<button class="btn btn-primary btn-fab btn-fab-mini btn-round">
|
||||||
@@ -23,12 +36,25 @@
|
|||||||
@foreach($eventType->schedule_model['periodes'] as $periode)
|
@foreach($eventType->schedule_model['periodes'] as $periode)
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-2 d-inline border-right border-bottom bg-light">
|
<div class="col-2 d-inline border-right border-bottom bg-light">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-9">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
<input type="text" placeholder="Période" class="form-control" value="{{$periode['name']}}" />
|
<input type="text" placeholder="Période" class="form-control" value="{{$periode['name']}}" />
|
||||||
<span class="form-control-feedback">
|
<span class="form-control-feedback">
|
||||||
<i class="material-icons">clear</i>
|
<i class="material-icons">clear</i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 text-right">
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<button id="modeSwitchPeriodeC{{$loop->index+1}}" class="btn-secondary dropdown-item m-1" onclick="selectCourseModePeriode('course',{{$loop->index+1}})">Mode "Cours" pour toute la période</button>
|
||||||
|
<button id="modeSwitchPeriodeO{{$loop->index+1}}" class="btn-secondary dropdown-item m-1" onclick="selectCourseModePeriode('other',{{$loop->index+1}})">Mode "Autre" pour toute la période</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<div class="form-group label-floating">
|
<div class="form-group label-floating">
|
||||||
@@ -45,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@foreach($eventType->schedule_model['niveaux'] as $niveau)
|
@foreach($eventType->schedule_model['niveaux'] as $niveau)
|
||||||
<div id="container-{{$loop->index+1}}-{{$loop->parent->index+1}}" niveau="{{$loop->index+1}}" periode="{{$loop->parent->index+1}}" class="col scheduleEditor-course">
|
<div id="container-{{$loop->index+1}}-{{$loop->parent->index+1}}" niveau="{{$loop->index+1}}" periode="{{$loop->parent->index+1}}" class="col m-0 border-bottom border-right scheduleEditor-course">
|
||||||
@loaderDot
|
@loaderDot
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card card-collapse" id="collmessagedelasemaine">
|
<div class="card card-collapse d-none" id="collmessagedelasemaine">
|
||||||
<div class="card-header" role="tab" id="headingTwo">
|
<div class="card-header" role="tab" id="headingTwo">
|
||||||
<h5 class="mb-0">
|
<h5 class="mb-0">
|
||||||
<a class="collapsed" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
<a class="collapsed" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card card-collapse" id="collschedule">
|
<div class="card card-collapse d-none" id="collschedule">
|
||||||
<div class="card-header" role="tab" id="headingThree">
|
<div class="card-header" role="tab" id="headingThree">
|
||||||
<h5 class="mb-0">
|
<h5 class="mb-0">
|
||||||
<a class="collapsed" data-toggle="collapse" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
<a class="collapsed" data-toggle="collapse" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="collapseThree" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion">
|
<div id="collapseThree" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion">
|
||||||
<div class="card-body" style="overflow: scroll">
|
<div class="card-body" style="overflow: scroll">
|
||||||
<div id="scheduleEditor" class="m-3" style="width: 90vw">
|
<div id="scheduleEditor" class="m-3" style="width: 110vw">
|
||||||
@loaderDot
|
@loaderDot
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ Route::middleware('auth:api')->group(function () {
|
|||||||
Route::get('/user/list', 'UserController@apiList')->middleware('perm:user_see');
|
Route::get('/user/list', 'UserController@apiList')->middleware('perm:user_see');
|
||||||
|
|
||||||
/** OCOM Route */
|
/** OCOM Route */
|
||||||
Route::get('/ocom/list', 'UserController@apiList')->middleware('perm:user_see');
|
Route::get('/ocom/list', 'OCOMController@jsonList')->middleware('perm:schedule_see');
|
||||||
|
Route::get('/ocom/{id}/name','OCOMController@getName')->middleware('perm:schedule_see');
|
||||||
|
|
||||||
/** Inventory Route */
|
/** Inventory Route */
|
||||||
Route::post('/item/delete', 'ItemController@destroy')->middleware('perm:inventory_delete');
|
Route::post('/item/delete', 'ItemController@destroy')->middleware('perm:inventory_delete');
|
||||||
|
|||||||
Reference in New Issue
Block a user