first commit backend
This commit is contained in:
commit
b8c9d560dd
|
@ -0,0 +1,18 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[docker-compose.yml]
|
||||||
|
indent_size = 4
|
|
@ -0,0 +1,11 @@
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.blade.php diff=html
|
||||||
|
*.css diff=css
|
||||||
|
*.html diff=html
|
||||||
|
*.md diff=markdown
|
||||||
|
*.php diff=php
|
||||||
|
|
||||||
|
/.github export-ignore
|
||||||
|
CHANGELOG.md export-ignore
|
||||||
|
.styleci.yml export-ignore
|
|
@ -0,0 +1,23 @@
|
||||||
|
/.phpunit.cache
|
||||||
|
/node_modules
|
||||||
|
/public/build
|
||||||
|
/public/hot
|
||||||
|
/public/storage
|
||||||
|
/storage/*.key
|
||||||
|
/storage/pail
|
||||||
|
/vendor
|
||||||
|
.env
|
||||||
|
.env.backup
|
||||||
|
.env.production
|
||||||
|
.phpactor.json
|
||||||
|
.phpunit.result.cache
|
||||||
|
Homestead.json
|
||||||
|
Homestead.yaml
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
/auth.json
|
||||||
|
/.fleet
|
||||||
|
/.idea
|
||||||
|
/.nova
|
||||||
|
/.vscode
|
||||||
|
/.zed
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exports;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Maatwebsite\Excel\Concerns\FromView;
|
||||||
|
|
||||||
|
class QuizExport implements FromView
|
||||||
|
{
|
||||||
|
public function view(): View
|
||||||
|
{
|
||||||
|
return view('pages.role_guru.quiz.excel_export_quiz');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exports;
|
||||||
|
|
||||||
|
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||||
|
|
||||||
|
class RekapExport implements FromCollection, WithHeadings
|
||||||
|
{
|
||||||
|
protected $rekap;
|
||||||
|
|
||||||
|
public function __construct($rekap)
|
||||||
|
{
|
||||||
|
$this->rekap = $rekap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collection()
|
||||||
|
{
|
||||||
|
return collect($this->rekap)->map(function ($item) {
|
||||||
|
return [
|
||||||
|
$item['matapelajaran'],
|
||||||
|
$item['judul_quiz'],
|
||||||
|
$item['nama_siswa'],
|
||||||
|
$item['tahun_ajaran'],
|
||||||
|
$item['kelas'],
|
||||||
|
$item['total_skor'],
|
||||||
|
$item['kkm'],
|
||||||
|
$item['persentase'],
|
||||||
|
$item['persentase'] >= $item['kkm'] ? 'Lulus' : 'Tidak Lulus',
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function headings(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'Mata Pelajaran',
|
||||||
|
'Judul Quiz',
|
||||||
|
'Nama Siswa',
|
||||||
|
'Tahun Ajaran',
|
||||||
|
'Kelas',
|
||||||
|
'Total Skor',
|
||||||
|
'KKM',
|
||||||
|
'Nilai (%)',
|
||||||
|
'Status',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exports;
|
||||||
|
|
||||||
|
use App\Models\SubmitTugas;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||||
|
|
||||||
|
class TugasDetailExport implements FromCollection, WithHeadings, WithMapping, WithStyles
|
||||||
|
{
|
||||||
|
protected $selectedKelas;
|
||||||
|
protected $selectedMatpel;
|
||||||
|
|
||||||
|
public function __construct($selectedKelas = null, $selectedMatpel = null)
|
||||||
|
{
|
||||||
|
$this->selectedKelas = $selectedKelas;
|
||||||
|
$this->selectedMatpel = $selectedMatpel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
public function collection()
|
||||||
|
{
|
||||||
|
$guruNip = Auth::user()->guru->nip;
|
||||||
|
|
||||||
|
$query = SubmitTugas::with(['siswa', 'tugas.mataPelajaran'])
|
||||||
|
->whereHas('tugas', function ($q) use ($guruNip) {
|
||||||
|
$q->where('guru_nip', $guruNip);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($this->selectedKelas) {
|
||||||
|
$query->whereHas('tugas', function ($q) {
|
||||||
|
$q->where('kelas', $this->selectedKelas);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->selectedMatpel) {
|
||||||
|
$query->whereHas('tugas', function ($q) {
|
||||||
|
$q->where('matapelajaran_id', $this->selectedMatpel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->orderBy('created_at', 'desc')->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function headings(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'No',
|
||||||
|
'Nama Tugas',
|
||||||
|
'Mata Pelajaran',
|
||||||
|
'Kelas',
|
||||||
|
'Nama Siswa',
|
||||||
|
'NISN',
|
||||||
|
'Tanggal Submit',
|
||||||
|
'Nilai',
|
||||||
|
'Status Nilai',
|
||||||
|
'Tenggat Waktu',
|
||||||
|
'Status Tenggat',
|
||||||
|
'Deskripsi Tugas'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function map($submitTugas): array
|
||||||
|
{
|
||||||
|
static $no = 1;
|
||||||
|
|
||||||
|
$tugas = $submitTugas->tugas;
|
||||||
|
$siswa = $submitTugas->siswa;
|
||||||
|
|
||||||
|
$statusNilai = $submitTugas->nilai !== null ? 'Sudah Dinilai' : 'Belum Dinilai';
|
||||||
|
$statusTenggat = \Carbon\Carbon::parse($tugas->tenggat)->isPast() ? 'Lewat Tenggat' : 'Masih Aktif';
|
||||||
|
|
||||||
|
return [
|
||||||
|
$no++,
|
||||||
|
$tugas->nama,
|
||||||
|
$tugas->mataPelajaran->nama ?? '-',
|
||||||
|
$tugas->kelas,
|
||||||
|
$siswa->nama ?? 'Siswa tidak ditemukan',
|
||||||
|
$submitTugas->nisn,
|
||||||
|
\Carbon\Carbon::parse($submitTugas->tanggal)->format('d/m/Y H:i'),
|
||||||
|
$submitTugas->nilai ?? '-',
|
||||||
|
$statusNilai,
|
||||||
|
\Carbon\Carbon::parse($tugas->tenggat)->format('d/m/Y'),
|
||||||
|
$statusTenggat,
|
||||||
|
$tugas->deskripsi ?? '-'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function styles(Worksheet $sheet)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
1 => [
|
||||||
|
'font' => ['bold' => true],
|
||||||
|
'fill' => [
|
||||||
|
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
|
||||||
|
'startColor' => ['rgb' => 'E2E8F0']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exports;
|
||||||
|
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||||
|
|
||||||
|
class TugasExport implements FromCollection, WithHeadings, WithMapping, WithStyles
|
||||||
|
{
|
||||||
|
protected $selectedKelas;
|
||||||
|
protected $selectedMatpel;
|
||||||
|
|
||||||
|
public function __construct($selectedKelas = null, $selectedMatpel = null)
|
||||||
|
{
|
||||||
|
$this->selectedKelas = $selectedKelas;
|
||||||
|
$this->selectedMatpel = $selectedMatpel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collection()
|
||||||
|
{
|
||||||
|
$guruNip = Auth::user()->guru->nip;
|
||||||
|
|
||||||
|
$query = Tugas::with(['mataPelajaran', 'submitTugas.siswa'])
|
||||||
|
->where('guru_nip', $guruNip);
|
||||||
|
|
||||||
|
if ($this->selectedKelas) {
|
||||||
|
$query->where('kelas', $this->selectedKelas);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->selectedMatpel) {
|
||||||
|
$query->where('matapelajaran_id', $this->selectedMatpel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->orderBy('created_at', 'desc')->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function headings(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'No',
|
||||||
|
'Nama Tugas',
|
||||||
|
'Mata Pelajaran',
|
||||||
|
'Kelas',
|
||||||
|
'Tanggal Dibuat',
|
||||||
|
'Tenggat Waktu',
|
||||||
|
'Jumlah Submit',
|
||||||
|
'Sudah Dinilai',
|
||||||
|
'Belum Dinilai',
|
||||||
|
'Rata-rata Nilai',
|
||||||
|
'Status Tenggat'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function map($tugas): array
|
||||||
|
{
|
||||||
|
static $no = 1;
|
||||||
|
|
||||||
|
$submitTugas = $tugas->submitTugas ?: collect();
|
||||||
|
$sudahDinilai = $submitTugas->whereNotNull('nilai')->count();
|
||||||
|
$totalSubmit = $submitTugas->count();
|
||||||
|
$belumDinilai = $totalSubmit - $sudahDinilai;
|
||||||
|
$rataRataNilai = $submitTugas->whereNotNull('nilai')->count() > 0
|
||||||
|
? number_format($submitTugas->whereNotNull('nilai')->avg('nilai'), 1)
|
||||||
|
: '-';
|
||||||
|
|
||||||
|
$statusTenggat = \Carbon\Carbon::parse($tugas->tenggat)->isPast() ? 'Lewat Tenggat' : 'Masih Aktif';
|
||||||
|
|
||||||
|
return [
|
||||||
|
$no++,
|
||||||
|
$tugas->nama,
|
||||||
|
$tugas->mataPelajaran->nama ?? '-',
|
||||||
|
$tugas->kelas,
|
||||||
|
\Carbon\Carbon::parse($tugas->tanggal)->format('d/m/Y'),
|
||||||
|
\Carbon\Carbon::parse($tugas->tenggat)->format('d/m/Y'),
|
||||||
|
$totalSubmit,
|
||||||
|
$sudahDinilai,
|
||||||
|
$belumDinilai,
|
||||||
|
$rataRataNilai,
|
||||||
|
$statusTenggat
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function styles(Worksheet $sheet)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
1 => [
|
||||||
|
'font' => ['bold' => true],
|
||||||
|
'fill' => [
|
||||||
|
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
|
||||||
|
'startColor' => ['rgb' => 'E2E8F0']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Repositories\AdminRepository;
|
||||||
|
use App\Repositories\UserRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use App\Models\Quizzes;
|
||||||
|
use App\Models\AuditLog;
|
||||||
|
|
||||||
|
class AdminController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
protected $paramUser;
|
||||||
|
|
||||||
|
public function __construct(AdminRepository $admin, UserRepository $user)
|
||||||
|
{
|
||||||
|
$this->param = $admin;
|
||||||
|
$this->paramUser = $user;
|
||||||
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$admin = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_admin.admin.index", compact("admin"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
return view("pages.role_admin.admin.create");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$dataUser = $request->validate([
|
||||||
|
'email' => 'required',
|
||||||
|
'role' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'nip' => 'required|string|size:18|unique:guru,nip',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'jk' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (Admin::where('nip', $data['nip'])->exists()) {
|
||||||
|
Alert::error("Terjadi Kesalahan", "NIP sudah terdaftar.");
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataUser['pass'] = $request->nip;
|
||||||
|
$user = $this->paramUser->store($dataUser);
|
||||||
|
|
||||||
|
$data["user_id"] = $user->id;
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di simpan.");
|
||||||
|
return redirect()->route("admin");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$admin = $this->param->find($id);
|
||||||
|
return view("pages.role_admin.admin.edit", compact("admin"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$dataUser = $request->validate([
|
||||||
|
'email' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'nip' => 'required|string|size:18',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'jk' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->paramUser->update($dataUser, $request->user_id);
|
||||||
|
$this->param->update($data, $id);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di ubah.");
|
||||||
|
return redirect()->route("admin");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->param->destroy($request->formid);
|
||||||
|
$this->paramUser->destroy($request->user_id);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Hapus.");
|
||||||
|
return redirect()->route("admin");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menampilkan halaman form pemindahan data
|
||||||
|
public function pindahDataPage()
|
||||||
|
{
|
||||||
|
$mataPelajaran = MataPelajaran::all();
|
||||||
|
$guru = Guru::all();
|
||||||
|
return view('pages.role_admin.pindah_data', compact('mataPelajaran', 'guru'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proses pemindahan data guru
|
||||||
|
public function pindahGuruMatpel(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'mata_pelajaran_id' => 'required|exists:matapelajaran,id',
|
||||||
|
'guru_lama_nip' => 'required|exists:guru,nip',
|
||||||
|
'guru_baru_nip' => 'required|exists:guru,nip',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($request->guru_lama_nip == $request->guru_baru_nip) {
|
||||||
|
Alert::error('Gagal', 'Guru lama dan guru baru tidak boleh sama.');
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
$mapel = MataPelajaran::where('id', $request->mata_pelajaran_id)
|
||||||
|
->where('guru_nip', $request->guru_lama_nip)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$mapel) {
|
||||||
|
Alert::error('Gagal', 'Guru lama bukan pengampu mata pelajaran yang dipilih.');
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update tugas
|
||||||
|
Tugas::where('guru_nip', $request->guru_lama_nip)
|
||||||
|
->where('matapelajaran_id', $request->mata_pelajaran_id)
|
||||||
|
->update(['guru_nip' => $request->guru_baru_nip]);
|
||||||
|
|
||||||
|
// Update guru pengampu pada tabel matapelajaran
|
||||||
|
MataPelajaran::where('id', $request->mata_pelajaran_id)
|
||||||
|
->where('guru_nip', $request->guru_lama_nip)
|
||||||
|
->update(['guru_nip' => $request->guru_baru_nip]);
|
||||||
|
|
||||||
|
Alert::success('Berhasil', 'Data guru berhasil dipindahkan.');
|
||||||
|
return redirect()->route('admin.pindah-data');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function auditLogPage()
|
||||||
|
{
|
||||||
|
$logs = AuditLog::with('user')->orderBy('created_at', 'desc')->paginate(30);
|
||||||
|
return view('pages.role_admin.audit_log', compact('logs'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class AuthController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function login(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
"login" => "required|string",
|
||||||
|
"password" => "required|string",
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Temukan user berdasarkan email atau NIP
|
||||||
|
$login = $request->login;
|
||||||
|
$user = User::where('email', $login)->first();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$siswa = Siswa::where('nisn', $login)->first();
|
||||||
|
if ($siswa)
|
||||||
|
$user = $siswa->user;
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$guru = Guru::where('nip', $login)->first();
|
||||||
|
if ($guru)
|
||||||
|
$user = $guru->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $token = DB::table('personal_access_tokens')->where('tokenable_id', $user->id)->first();
|
||||||
|
// if (!is_null($token)) {
|
||||||
|
// return $this->errorApiResponse("User sudah login di device lain. Harap logout terlebih dahulu.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// Jika user ditemukan dan password cocok
|
||||||
|
if ($user && Hash::check($request->password, $user->password)) {
|
||||||
|
$token = $user->createToken('Mobile')->plainTextToken;
|
||||||
|
$user = $user->role == "siswa" ? $siswa : $guru;
|
||||||
|
|
||||||
|
return $this->okApiResponse([
|
||||||
|
'token' => $token,
|
||||||
|
'user' => $user,
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->errorApiResponse('Login gagal. Cek kembali kredensial Anda.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request)
|
||||||
|
{
|
||||||
|
$request->user()->currentAccessToken()->delete();
|
||||||
|
return $this->okApiResponse([], 'Berhsasil Logout.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function user(Request $request)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
$user = $request->user();
|
||||||
|
if ($user->role == 'siswa') {
|
||||||
|
$data = Siswa::where('user_id', $user->id);
|
||||||
|
} else {
|
||||||
|
$data = Guru::where('user_id', $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $data->with('user')->first();
|
||||||
|
|
||||||
|
return $this->okApiResponse([
|
||||||
|
'user' => $data,
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class KelasContoller extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$kelas = Kelas::orderBy("nama", "ASC")->get();
|
||||||
|
return $this->okApiResponse($kelas);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\Materi;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class MataPelajaranController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
public function getMatpel(Request $request)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
$query = [];
|
||||||
|
$user = $request->user();
|
||||||
|
if ($user->role == 'siswa') {
|
||||||
|
$data = Siswa::where('user_id', $user->id);
|
||||||
|
} else {
|
||||||
|
$data = Guru::where('user_id', $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $data->with('user')->first();
|
||||||
|
|
||||||
|
if ($data->user->role == "siswa") {
|
||||||
|
$query = MataPelajaran::where(function ($query) use ($data) {
|
||||||
|
$query->where('kelas', $data->kelas)
|
||||||
|
->where('tahun_ajaran', $data->tahun_ajaran);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$query = MataPelajaran::where(function ($query) use ($data, $request) {
|
||||||
|
$query->where('guru_nip', $data->nip)
|
||||||
|
->where("kelas", $request->kelas)
|
||||||
|
->where("tahun_ajaran", $request->tahun_ajaran);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$query = $query->with(['guru', 'materi'])->get();
|
||||||
|
|
||||||
|
$result = $query->map(function ($item) {
|
||||||
|
$materi = $item->materi ?? collect();
|
||||||
|
|
||||||
|
$jumlahBuku = $materi->where('type', 'buku')->count();
|
||||||
|
$jumlahVideo = $materi->where('type', 'video')->count();
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
$item->toArray(),
|
||||||
|
[
|
||||||
|
'jumlah_buku' => $jumlahBuku,
|
||||||
|
'jumlah_video' => $jumlahVideo,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->okApiResponse($result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMatpelSimple(Request $request)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
$query = [];
|
||||||
|
$user = $request->user();
|
||||||
|
if ($user->role == 'siswa') {
|
||||||
|
$data = Siswa::where('user_id', $user->id);
|
||||||
|
} else {
|
||||||
|
$data = Guru::where('user_id', $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $data->with('user')->first();
|
||||||
|
|
||||||
|
if ($data->user->role == "siswa") {
|
||||||
|
$query = MataPelajaran::where(function ($query) use ($data) {
|
||||||
|
$query->where('kelas', $data->kelas)
|
||||||
|
->where('tahun_ajaran', $data->tahun_ajaran);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$query = MataPelajaran::where(function ($query) use ($data) {
|
||||||
|
$query->where('guru_nip', $data->nip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$query = $query->with('guru')->get();
|
||||||
|
|
||||||
|
return $this->okApiResponse($query);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Repositories\MateriRepository;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class MateriController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function __construct(MateriRepository $materi)
|
||||||
|
{
|
||||||
|
$this->param = $materi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMateri(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = [];
|
||||||
|
$user = $request->user();
|
||||||
|
if ($user->role == 'siswa') {
|
||||||
|
$data = Siswa::where('user_id', $user->id);
|
||||||
|
} else {
|
||||||
|
$data = Guru::where('user_id', $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $data->with('user')->first();
|
||||||
|
|
||||||
|
$result = $this->param->getDataApi($request->id_matpel, $request->semester, $request->type, $data);
|
||||||
|
return $this->okApiResponse($result);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $this->errorApiResponse("Terjadi Kesalahan " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\QuizAttempts;
|
||||||
|
use App\Models\QuizLevelSetting;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class QuizAnalysisController extends Controller
|
||||||
|
{
|
||||||
|
static function getSkor($first)
|
||||||
|
{
|
||||||
|
$quizId = $first->quiz_id;
|
||||||
|
$quizLevelSettings = QuizLevelSetting::where('quiz_id', $quizId)->first();
|
||||||
|
$jumlahSoalPerLevel = json_decode($quizLevelSettings->jumlah_soal_per_level, true);
|
||||||
|
$totalSkorLevel = 0;
|
||||||
|
|
||||||
|
foreach (json_decode($quizLevelSettings->skor_level) as $key => $value) {
|
||||||
|
$totalSkorLevel += $value * (int) $jumlahSoalPerLevel[$key];
|
||||||
|
}
|
||||||
|
return $totalSkorLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function analisis(Request $request)
|
||||||
|
{
|
||||||
|
$user = Auth::user()->siswa;
|
||||||
|
|
||||||
|
// Ambil semua attempt dengan relasi quizzes dan mata pelajaran
|
||||||
|
$attempts = QuizAttempts::where('nisn', $user->nisn)
|
||||||
|
->with(['quizzes.mataPelajaran'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Kelompokkan berdasarkan mata_pelajaran_id dan hitung rata-rata skor
|
||||||
|
$grouped = $attempts->groupBy(function ($item) {
|
||||||
|
return $item->quizzes->mataPelajaran->id;
|
||||||
|
});
|
||||||
|
|
||||||
|
$avgScores = $grouped->map(function ($items) {
|
||||||
|
$first = $items->first(); // untuk ambil info nama mapel
|
||||||
|
$avg = $items->avg('skor');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'mapel_id' => $first->quizzes->mataPelajaran->id,
|
||||||
|
'mapel' => $first->quizzes->mataPelajaran->nama,
|
||||||
|
'rata_rata_skor' => $avg,
|
||||||
|
'persentase' => round(($avg / $this->getSkor($first)) * 100),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Urutkan berdasarkan skor rata-rata (desc dan asc)
|
||||||
|
$kelebihan = $avgScores->sortByDesc('rata_rata_skor')->take(2);
|
||||||
|
$kelebihanMapelIds = $kelebihan->pluck('mapel_id')->toArray();
|
||||||
|
|
||||||
|
$kekurangan = $avgScores->whereNotIn('mapel_id', $kelebihanMapelIds)
|
||||||
|
->sortBy('rata_rata_skor')
|
||||||
|
->take(2);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'kelebihan' => array_values($kelebihan->toArray()),
|
||||||
|
'kekurangan' => array_values($kekurangan->toArray())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\QuizAttemptAnswers;
|
||||||
|
use App\Models\QuizAttempts;
|
||||||
|
use App\Models\QuizLevelSetting;
|
||||||
|
use App\Models\QuizQuestions;
|
||||||
|
use App\Repositories\QuizRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class QuizController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
protected $param;
|
||||||
|
public function __construct(QuizRepository $quizzes)
|
||||||
|
{
|
||||||
|
$this->param = $quizzes;
|
||||||
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$data = $this->param->apiGetQuizzes($request->matapelajaran_id);
|
||||||
|
return $this->okApiResponse($data);
|
||||||
|
}
|
||||||
|
public function quizGuru(Request $request)
|
||||||
|
{
|
||||||
|
$data = $this->param->apiGetQuizzesGuru($request, $request->matapelajaran_id);
|
||||||
|
return $this->okApiResponse($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'quiz_id' => 'required|exists:quizzes,id',
|
||||||
|
'nisn' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$quizLevelSettings = QuizLevelSetting::where('quiz_id', $request->quiz_id)->first();
|
||||||
|
$level = [];
|
||||||
|
foreach (json_decode($quizLevelSettings->jumlah_soal_per_level) as $key => $value) {
|
||||||
|
$lvlNumber = preg_replace('/[^0-9]/', '', $key);
|
||||||
|
$level['fase' . $lvlNumber] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attempt = QuizAttempts::create([
|
||||||
|
'quiz_id' => $request->quiz_id,
|
||||||
|
'nisn' => $request->nisn,
|
||||||
|
'skor' => 0,
|
||||||
|
'level_akhir' => $quizLevelSettings->level_awal,
|
||||||
|
'fase' => $quizLevelSettings->level_awal,
|
||||||
|
'benar' => json_encode($level),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'attempt_id' => $attempt->id,
|
||||||
|
'message' => 'Quiz dimulai.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function nextQuestion($attempt_id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->param->nextQuestion($attempt_id);
|
||||||
|
return $this->okApiResponse($data);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->errorApiResponse($e->getMessage(), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function answer(Request $request, $attempt_id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->param->answer($request, $attempt_id);
|
||||||
|
return $this->okApiResponse($data);
|
||||||
|
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||||
|
return $this->errorApiResponse('Validation error: ' . $e->getMessage(), 422);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->errorApiResponse($e->getMessage(), 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFinishQuiz(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->param->getFinishQuiz($request->quiz_id);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->errorApiResponse($e->getMessage(), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTopFive(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$query = QuizAttempts::with('siswa')
|
||||||
|
->where('quiz_id', $request->quiz_id)
|
||||||
|
->orderByDesc('skor')
|
||||||
|
->take(5)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$skorMe = QuizAttempts::select('skor')
|
||||||
|
->where('nisn', Auth::user()->siswa->nisn)
|
||||||
|
->where('quiz_id', $request->quiz_id)
|
||||||
|
->orderByDesc('skor')->first();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'skor_me' => $skorMe,
|
||||||
|
'data' => $query,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getNilai($first)
|
||||||
|
{
|
||||||
|
$quizId = $first->quiz_id;
|
||||||
|
$quizLevelSettings = QuizLevelSetting::where('quiz_id', $quizId)->first();
|
||||||
|
$jumlahSoalPerLevel = json_decode($quizLevelSettings->jumlah_soal_per_level, true);
|
||||||
|
$totalSkorLevel = 0;
|
||||||
|
|
||||||
|
foreach (json_decode($quizLevelSettings->skor_level) as $key => $value) {
|
||||||
|
$totalSkorLevel += $value * (int) $jumlahSoalPerLevel[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
"total_skor_level" => $totalSkorLevel,
|
||||||
|
"kkm" => $quizLevelSettings->kkm,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApiQuizGuru(Request $request)
|
||||||
|
{
|
||||||
|
$query = QuizAttempts::with(['quizzes', 'siswa'])
|
||||||
|
->where(function ($q) use ($request) {
|
||||||
|
$q->where('quiz_id', $request->quiz_id);
|
||||||
|
})->whereHas('siswa', function ($q) use ($request) {
|
||||||
|
$q->where('kelas', $request->kelas)
|
||||||
|
->where('tahun_ajaran', $request->tahun_ajaran);
|
||||||
|
})->get();
|
||||||
|
|
||||||
|
$avgScores = $query->map(function ($items) {
|
||||||
|
$first = $items->first(); // untuk ambil info nama mapel
|
||||||
|
$avg = $items->avg('skor');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'nama' => $first->siswa->nama,
|
||||||
|
'mapel_id' => $first->quizzes->mataPelajaran->id,
|
||||||
|
'mapel' => $first->quizzes->mataPelajaran->nama,
|
||||||
|
'skor' => $first->skor,
|
||||||
|
'persentase' => round(($avg / $this->getNilai($first)['total_skor_level']) * 100),
|
||||||
|
'kkm' => $this->getNilai($first)['kkm'],
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->okApiResponse($avgScores);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function debugQuiz($attempt_id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$attempt = QuizAttempts::findOrFail($attempt_id);
|
||||||
|
$questions = QuizQuestions::where('quiz_id', $attempt->quiz_id)->get();
|
||||||
|
$answeredQuestions = QuizAttemptAnswers::where('attempt_id', $attempt_id)->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'attempt' => $attempt,
|
||||||
|
'total_questions' => $questions->count(),
|
||||||
|
'answered_questions' => $answeredQuestions->count(),
|
||||||
|
'questions_by_level' => $questions->groupBy('level'),
|
||||||
|
'answered_question_ids' => $answeredQuestions->pluck('question_id'),
|
||||||
|
'current_level' => $attempt->level_akhir,
|
||||||
|
'current_fase' => $attempt->fase,
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->errorApiResponse($e->getMessage(), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function autoFinish($attempt_id)
|
||||||
|
{
|
||||||
|
$attempt = \App\Models\QuizAttempts::findOrFail($attempt_id);
|
||||||
|
|
||||||
|
// Ambil semua soal quiz
|
||||||
|
$allQuestions = \App\Models\QuizQuestions::where('quiz_id', $attempt->quiz_id)->pluck('id')->toArray();
|
||||||
|
|
||||||
|
// Ambil semua question_id yang sudah dijawab
|
||||||
|
$answered = \App\Models\QuizAttemptAnswers::where('attempt_id', $attempt_id)->pluck('question_id')->toArray();
|
||||||
|
|
||||||
|
// Cari soal yang belum dijawab
|
||||||
|
$unanswered = array_diff($allQuestions, $answered);
|
||||||
|
|
||||||
|
foreach ($unanswered as $questionId) {
|
||||||
|
\App\Models\QuizAttemptAnswers::create([
|
||||||
|
'attempt_id' => $attempt->id,
|
||||||
|
'question_id' => $questionId,
|
||||||
|
'jawaban_siswa' => '',
|
||||||
|
'benar' => 0,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hitung penilaian berdasarkan jawaban yang benar-benar dikerjakan
|
||||||
|
$jawaban_benar = \App\Models\QuizAttemptAnswers::where('attempt_id', $attempt->id)->where('benar', 1)->count();
|
||||||
|
$jawaban_salah = \App\Models\QuizAttemptAnswers::where('attempt_id', $attempt->id)->where('benar', 0)->count();
|
||||||
|
$total_dikerjakan = $jawaban_benar + $jawaban_salah;
|
||||||
|
$skor = $attempt->skor;
|
||||||
|
$persentase = $total_dikerjakan > 0 ? round(($jawaban_benar / $total_dikerjakan) * 100) : 0;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => true,
|
||||||
|
'message' => 'Quiz auto-finished successfully',
|
||||||
|
'data' => [
|
||||||
|
'jawaban_benar' => $jawaban_benar,
|
||||||
|
'jawaban_salah' => $jawaban_salah,
|
||||||
|
'total_dikerjakan' => $total_dikerjakan,
|
||||||
|
'skor' => $skor,
|
||||||
|
'persentase' => $persentase,
|
||||||
|
'attempt' => $attempt
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Http\Resources\SubmitTugasResource;
|
||||||
|
use App\Repositories\ApiSubmitTugasRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class SubmitTugasController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function __construct(ApiSubmitTugasRepository $submitTugas)
|
||||||
|
{
|
||||||
|
$this->param = $submitTugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$data = $this->param->store($request);
|
||||||
|
return $this->okApiResponse(new SubmitTugasResource($data), "Submit Tugas Berhasil");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail(Request $request)
|
||||||
|
{
|
||||||
|
$data = $this->param->detail($request);
|
||||||
|
return $this->okApiResponse(new SubmitTugasResource($data), "Berhasil get submit tugas");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
$data = $this->param->update($request);
|
||||||
|
return $this->okApiResponse(new SubmitTugasResource($data), "Update Tugas Berhasil");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateNilai(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'id' => 'required|exists:submit_tugas,id',
|
||||||
|
'nilai' => 'required|integer|min:0|max:100'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $this->param->update($request);
|
||||||
|
return $this->okApiResponse(new SubmitTugasResource($data), "Nilai berhasil diperbarui");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class TahunAjaranController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function getTahunAjaran(Request $request)
|
||||||
|
{
|
||||||
|
$data = TahunAjaran::where("status", "aktif")->get();
|
||||||
|
return $this->okApiResponse($data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Repositories\ApiTugasRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class TugasController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function __construct(ApiTugasRepository $tugas)
|
||||||
|
{
|
||||||
|
$this->param = $tugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTugas(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = [];
|
||||||
|
$user = $request->user();
|
||||||
|
if ($user->role == 'siswa') {
|
||||||
|
$data = Siswa::where('user_id', $user->id);
|
||||||
|
} else {
|
||||||
|
$data = Guru::where('user_id', $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $data->with('user')->first();
|
||||||
|
|
||||||
|
$result = $this->param->getDataApi($data, $request);
|
||||||
|
return $this->okApiResponse($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->errorApiResponse("Error : " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubmitTugasSiswa(Request $request)
|
||||||
|
{
|
||||||
|
$result = $this->param->getSubmitTugasSiswa($request);
|
||||||
|
return $this->okApiResponse($result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\User;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class AuthController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view("pages.auth.index");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request->validate([
|
||||||
|
"login" => "required|string",
|
||||||
|
"password" => "required|string",
|
||||||
|
]);
|
||||||
|
|
||||||
|
$login = $request->login;
|
||||||
|
$user = User::where('email', $login)->first();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$admin = Admin::where('nip', $login)->first();
|
||||||
|
if ($admin) {
|
||||||
|
$user = $admin->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$guru = Guru::where('nip', $login)->first();
|
||||||
|
if ($guru) {
|
||||||
|
$user = $guru->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user && Hash::check($request->password, $user->password)) {
|
||||||
|
Auth::login($user);
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
if ($user->role == 'admin') {
|
||||||
|
return redirect()->route('/');
|
||||||
|
} elseif ($user->role == 'guru') {
|
||||||
|
return redirect()->route('dashboard.guru');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('login')->with('error', "Nip atau Password anda salah!");
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error("Error saat login: " . $e->getMessage());
|
||||||
|
return redirect()->route("login")->with("error", "Terjadi kesalahan sistem. Silahkan coba lagi. $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Auth::logout();
|
||||||
|
$request->session()->invalidate();
|
||||||
|
// DB::table('sessions')->where('user_id', Auth::user()->nip)->delete();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
return redirect()->route('login');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error("Error saat login: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
abstract class Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Repositories\DashboardRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class DashboardController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(DashboardRepository $dashboard)
|
||||||
|
{
|
||||||
|
$this->param = $dashboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$tahunAjaran = $request->get('tahun_ajaran');
|
||||||
|
$kelas = $request->get('kelas');
|
||||||
|
$dashboard = $this->param->getData($tahunAjaran, $kelas);
|
||||||
|
return view('pages.role_admin.admin_dashboard.index', compact('dashboard'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexAdmin()
|
||||||
|
{
|
||||||
|
$dashboard = $this->param->getData();
|
||||||
|
return view("pages.role_guru.dashboard.index", compact("dashboard"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\AuditLog;
|
||||||
|
use App\Repositories\GuruRepository;
|
||||||
|
use App\Repositories\UserRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class GuruController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
protected $param2;
|
||||||
|
|
||||||
|
public function __construct(GuruRepository $guru, UserRepository $userRepository)
|
||||||
|
{
|
||||||
|
$this->param = $guru;
|
||||||
|
$this->param2 = $userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$guru = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_admin.guru.index", compact("guru"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
return view("pages.role_admin.guru.create");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$dataUser = $request->validate([
|
||||||
|
'email' => 'required',
|
||||||
|
'role' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'nip' => 'required|string|size:18|unique:guru,nip',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'jk' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (Guru::where('nip', $data['nip'])->exists()) {
|
||||||
|
Alert::error("Terjadi Kesalahan", "NIP sudah terdaftar.");
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataUser['pass'] = $request->nip;
|
||||||
|
$user = $this->param2->store($dataUser);
|
||||||
|
|
||||||
|
$data["user_id"] = $user->id;
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di simpan.");
|
||||||
|
return redirect()->route("guru");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$guru = $this->param->find($id);
|
||||||
|
return view("pages.role_admin.guru.edit", compact("guru"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$dataUser = $request->validate([
|
||||||
|
'email' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'nip' => 'required|string|size:18',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'jk' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param2->update($dataUser, $request->user_id);
|
||||||
|
$this->param->update($data, $id);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di ubah.");
|
||||||
|
return redirect()->route("guru");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$guru = Guru::find($request->formid);
|
||||||
|
if (!$guru) {
|
||||||
|
Alert::error('Gagal', 'Guru tidak ditemukan.');
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
$nip = trim(strtoupper($guru->nip));
|
||||||
|
// Cek apakah guru masih menjadi wali kelas (robust, ignore case & space)
|
||||||
|
$isWali = Kelas::whereRaw('TRIM(UPPER(nip_wali)) = ?', [$nip])->exists();
|
||||||
|
if ($isWali) {
|
||||||
|
Alert::error('Gagal', 'Tidak dapat menghapus guru karena masih menjadi wali kelas. Silakan ganti wali kelas terlebih dahulu.');
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
$this->param->destroy($request->formid);
|
||||||
|
$this->param2->destroy($request->user_id);
|
||||||
|
// Audit log
|
||||||
|
AuditLog::create([
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'action' => 'delete_guru',
|
||||||
|
'description' => 'Menghapus guru: ' . $guru->nama . ' (' . $guru->nip . ')',
|
||||||
|
]);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di hapus data.");
|
||||||
|
return redirect()->route("guru");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Repositories\GuruDashboardRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class GuruDashboardController extends Controller
|
||||||
|
{
|
||||||
|
protected $guruDashboardRepository;
|
||||||
|
|
||||||
|
public function __construct(GuruDashboardRepository $guruDashboardRepository)
|
||||||
|
{
|
||||||
|
$this->guruDashboardRepository = $guruDashboardRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$tahunAjaran = $request->get('tahun_ajaran', 'all');
|
||||||
|
$kelas = $request->get('kelas', 'all');
|
||||||
|
$quizStatus = $request->get('quiz_status', 'all');
|
||||||
|
|
||||||
|
$dashboard = $this->guruDashboardRepository->getDashboardData($tahunAjaran, $kelas, $quizStatus);
|
||||||
|
|
||||||
|
return view('pages.role_admin.guru_dashboard.index', compact('dashboard'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Repositories\KelasRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class KelasContoller extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
protected $paramUser;
|
||||||
|
|
||||||
|
public function __construct(KelasRepository $kelas)
|
||||||
|
{
|
||||||
|
$this->param = $kelas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$kelas = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_admin.kelas.index", compact("kelas"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
return view("pages.role_admin.kelas.create");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'nama' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di simpan.");
|
||||||
|
return redirect()->route("kelas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
// $kelas = Kelas::find($id);
|
||||||
|
// return view("pages.role_admin.kelas.edit", compact("kelas"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
// try {
|
||||||
|
|
||||||
|
// $data = $request->validate([
|
||||||
|
// 'nama' => 'required|string',
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
// $this->param->update($data, $id);
|
||||||
|
// Alert::success("Berhasil", "Data Berhasil di ubah.");
|
||||||
|
// return redirect()->route("kelas");
|
||||||
|
// } catch (\Exception $e) {
|
||||||
|
// Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
// return back()->withInput();
|
||||||
|
// } catch (QueryException $e) {
|
||||||
|
// Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
// return back()->withInput();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->param->destroy($request->formkelas);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Hapus.");
|
||||||
|
return redirect()->route("kelas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Models\AuditLog;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use App\Repositories\MataPelajaranRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class MataPelajaranController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(MataPelajaranRepository $mataPelajaran)
|
||||||
|
{
|
||||||
|
$this->param = $mataPelajaran;
|
||||||
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$mataPelajaran = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_admin.mata_pelajaran.index", compact("mataPelajaran"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$guru = Guru::all();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
return view("pages.role_admin.mata_pelajaran.create", compact("guru", "kelas", "tahunAjaran"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'nama' => 'required',
|
||||||
|
'guru_nip' => 'required',
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Tambahkan.");
|
||||||
|
return redirect()->route("mata-pelajaran");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$mataPelajaran = $this->param->find($id);
|
||||||
|
$guru = Guru::all();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
return view("pages.role_admin.mata_pelajaran.edit", compact(["mataPelajaran", "guru", "kelas", "tahunAjaran"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'nama' => 'required',
|
||||||
|
'guru_nip' => 'required',
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$old = $this->param->find($id);
|
||||||
|
$isManual = $old->guru_nip !== $data['guru_nip'];
|
||||||
|
$this->param->update($data, $id);
|
||||||
|
// Audit log
|
||||||
|
AuditLog::create([
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'action' => 'update_pengampu_mapel',
|
||||||
|
'description' => 'Update pengampu mapel: ' . $old->nama . ' (' . $old->id . ') dari ' . $old->guru_nip . ' ke ' . $data['guru_nip'],
|
||||||
|
]);
|
||||||
|
if ($isManual) {
|
||||||
|
Alert::warning('Perhatian', 'Anda mengganti pengampu mata pelajaran tanpa fitur pemindahan data. Data tugas dan submit tugas lama tetap milik guru sebelumnya.');
|
||||||
|
} else {
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Ubah.");
|
||||||
|
}
|
||||||
|
return redirect()->route("mata-pelajaran");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,232 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\RoleGuru;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\Materi;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Repositories\MateriRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class MateriController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(MateriRepository $materi)
|
||||||
|
{
|
||||||
|
$this->param = $materi;
|
||||||
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$materi = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_guru.materi.index", compact("materi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail($id)
|
||||||
|
{
|
||||||
|
$materiDetail = Materi::find($id);
|
||||||
|
return view("pages.role_guru.materi.detail", compact("materiDetail"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
$matpel = MataPelajaran::where('guru_nip', Auth::user()->guru->nip)->get();
|
||||||
|
return view("pages.role_guru.materi.create", compact('matpel', 'tahunAjaran'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$tanggal = $request->input('tanggal');
|
||||||
|
$guruNip = $request->user()->guru->nip;
|
||||||
|
|
||||||
|
// dd($request->file('path'));
|
||||||
|
|
||||||
|
if ($request->type == "buku") {
|
||||||
|
// Validasi untuk buku (file PDF)
|
||||||
|
$validated = $request->validate([
|
||||||
|
'matapelajaran_id' => 'required',
|
||||||
|
'semester' => 'required',
|
||||||
|
'type' => 'required',
|
||||||
|
'judul_materi' => 'required',
|
||||||
|
'deskripsi' => 'required',
|
||||||
|
'path' => 'required|file|mimes:pdf|max:5120',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$judul = Str::slug(Str::limit($request->judul_materi, 50));
|
||||||
|
$ext = $request->file('path')->getClientOriginalExtension();
|
||||||
|
$namaFile = "{$guruNip}_{$tanggal}_{$judul}.{$ext}";
|
||||||
|
|
||||||
|
$path = $request->file('path')->storeAs('materi', $namaFile, 'public');
|
||||||
|
$validated['path'] = $path;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Validasi untuk video (link video)
|
||||||
|
$validated = $request->validate([
|
||||||
|
'matapelajaran_id' => 'required',
|
||||||
|
'semester' => 'required',
|
||||||
|
'type' => 'required',
|
||||||
|
'judul_materi' => 'required',
|
||||||
|
'deskripsi' => 'required',
|
||||||
|
'path' => 'required|string', // path link video
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validated['tanggal'] = $tanggal;
|
||||||
|
|
||||||
|
$this->param->store($validated);
|
||||||
|
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di simpan.");
|
||||||
|
return redirect()->route("materi");
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($e instanceof \Illuminate\Validation\ValidationException) {
|
||||||
|
$errors = $e->validator->errors()->all();
|
||||||
|
Alert::error("Validasi Gagal", implode("\n", $errors));
|
||||||
|
} else {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
}
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
$matpel = MataPelajaran::where('guru_nip', Auth::user()->guru->nip)->get();
|
||||||
|
$materi = $this->param->find($id);
|
||||||
|
return view("pages.role_guru.materi.edit", compact(["tahunAjaran", "matpel", "materi"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$tanggal = $request->input('tanggal');
|
||||||
|
$guruNip = $request->user()->guru->nip;
|
||||||
|
|
||||||
|
$materi = $this->param->find($id);
|
||||||
|
|
||||||
|
if (!$materi) {
|
||||||
|
Alert::error("Tidak ditemukan", "Data materi tidak ditemukan.");
|
||||||
|
return redirect()->route("materi");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->type == "buku") {
|
||||||
|
$validated = $request->validate([
|
||||||
|
'matapelajaran_id' => 'required',
|
||||||
|
'semester' => 'required',
|
||||||
|
'type' => 'required',
|
||||||
|
'judul_materi' => 'required',
|
||||||
|
'deskripsi' => 'required',
|
||||||
|
'path' => 'nullable|file|mimes:pdf|max:5120', // Boleh kosong saat update
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Jika ada file baru diunggah
|
||||||
|
if ($request->hasFile('path')) {
|
||||||
|
// Hapus file lama jika ada
|
||||||
|
if ($materi->path && Storage::disk('public')->exists($materi->path)) {
|
||||||
|
Storage::disk('public')->delete($materi->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$judul = Str::slug(Str::limit($request->judul_materi, 50));
|
||||||
|
$ext = $request->file('path')->getClientOriginalExtension();
|
||||||
|
$namaFile = "{$guruNip}_{$tanggal}_{$judul}.{$ext}";
|
||||||
|
|
||||||
|
$path = $request->file('path')->storeAs('materi', $namaFile, 'public');
|
||||||
|
$validated['path'] = $path;
|
||||||
|
} else {
|
||||||
|
$validated['path'] = $materi->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$validated = $request->validate([
|
||||||
|
'matapelajaran_id' => 'required',
|
||||||
|
'semester' => 'required',
|
||||||
|
'type' => 'required',
|
||||||
|
'judul_materi' => 'required',
|
||||||
|
'deskripsi' => 'required',
|
||||||
|
'path' => 'required|string', // Link video
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validated['tanggal'] = $tanggal;
|
||||||
|
|
||||||
|
$this->param->update($validated, $id);
|
||||||
|
|
||||||
|
Alert::success("Berhasil", "Data berhasil diperbarui.");
|
||||||
|
return redirect()->route("materi");
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($e instanceof \Illuminate\Validation\ValidationException) {
|
||||||
|
$errors = $e->validator->errors()->all();
|
||||||
|
Alert::error("Validasi Gagal", implode("\n", $errors));
|
||||||
|
} else {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
}
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$materi = $this->param->find($request->formid);
|
||||||
|
|
||||||
|
if ($materi->type === 'buku' && $materi->path) {
|
||||||
|
// Hapus file PDF dari storage/public/materi
|
||||||
|
Storage::disk('public')->delete($materi->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->param->destroy($materi->id);
|
||||||
|
Alert::success("Berhasil", "Data berhasil dihapus.");
|
||||||
|
return redirect()->route("materi"); // sesuaikan dengan route kamu
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,503 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\RoleGuru;
|
||||||
|
|
||||||
|
use App\Exports\QuizExport;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\QuizLevelSetting;
|
||||||
|
use App\Models\QuizQuestions;
|
||||||
|
use App\Models\Quizzes;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Notifications\QuizBaruNotification;
|
||||||
|
use App\Repositories\QuizRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Maatwebsite\Excel\Concerns\FromView;
|
||||||
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class QuizController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(QuizRepository $quiz)
|
||||||
|
{
|
||||||
|
$this->param = $quiz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$nip = Auth::user()->guru->nip;
|
||||||
|
$matpel = MataPelajaran::where('guru_nip', $nip)->get();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
|
||||||
|
// Get quizzes created by this teacher
|
||||||
|
$quiz = Quizzes::with(['mataPelajaran', 'quizLevelSetting'])
|
||||||
|
->whereHas('mataPelajaran', function ($q) use ($nip) {
|
||||||
|
$q->where('guru_nip', $nip);
|
||||||
|
})
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view("pages.role_guru.quiz.index", compact(['matpel', 'kelas', 'tahunAjaran', 'quiz']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuizByMatpel($id)
|
||||||
|
{
|
||||||
|
$nip = Auth::user()->guru->nip;
|
||||||
|
$quizzes = Quizzes::where('matapelajaran_id', $id)
|
||||||
|
->whereHas('mataPelajaran', function ($q) use ($nip) {
|
||||||
|
$q->where('guru_nip', $nip);
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json($quizzes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function excelDownload()
|
||||||
|
{
|
||||||
|
return Excel::download(new QuizExport, "format_excel_untuk_quiz.xlsx");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preview(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'file' => 'required|mimes:xlsx,xls'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = Excel::toArray([], $request->file('file'));
|
||||||
|
|
||||||
|
// Ambil sheet pertama
|
||||||
|
$rows = $data[0];
|
||||||
|
|
||||||
|
$filteredRows = [];
|
||||||
|
$jumlahSoalPerLevel = [];
|
||||||
|
$totalSoalPeLevel = [];
|
||||||
|
$batasNaikLevel = [];
|
||||||
|
$skorLevel = [];
|
||||||
|
|
||||||
|
foreach ($rows as $index => $row) {
|
||||||
|
if ($index == 0 || !empty($row[1])) {
|
||||||
|
$filteredRows[] = $row;
|
||||||
|
|
||||||
|
$level = $row[3];
|
||||||
|
$skor = $row[8];
|
||||||
|
if (!empty($level) && $index != 0) {
|
||||||
|
$key = 'level' . $level;
|
||||||
|
if (!isset($jumlahSoalPerLevel[$key])) {
|
||||||
|
$jumlahSoalPerLevel[$key] = 0;
|
||||||
|
$totalSoalPeLevel[$key] = 0;
|
||||||
|
}
|
||||||
|
$jumlahSoalPerLevel[$key]++;
|
||||||
|
$totalSoalPeLevel[$key]++;
|
||||||
|
$skorLevel[$key] = $skor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hitung batas naik level = 50% dari jumlah soal di level tersebut
|
||||||
|
foreach ($jumlahSoalPerLevel as $key => $jumlah) {
|
||||||
|
// Ambil level dari key, contoh: 'level2' → 2
|
||||||
|
$level = str_replace('level', '', $key);
|
||||||
|
$keyFase = 'fase' . $level;
|
||||||
|
|
||||||
|
// Hitung 50% lalu dibulatkan ke atas (ceil)
|
||||||
|
$batasNaikLevel[$keyFase] = (int) ceil($jumlah * 0.5);
|
||||||
|
|
||||||
|
$jumlahSoalPerLevel[$key] = (int) ceil($jumlah * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$soalCount = count($filteredRows) - 1;
|
||||||
|
|
||||||
|
// Simpan preview dan jumlah soal ke session
|
||||||
|
Session::put('judul', $request->judul);
|
||||||
|
Session::put('deskripsi', $request->deskripsi);
|
||||||
|
Session::put('matapelajaran_id', $request->matapelajaran_id);
|
||||||
|
Session::put('waktu', $request->waktu);
|
||||||
|
Session::put('preview_soal', $filteredRows);
|
||||||
|
Session::put('total_soal', $soalCount);
|
||||||
|
Session::put('total_soal_tampil', $request->total_soal_tampil ?? 20);
|
||||||
|
Session::put('uploaded_filename', $request->file('file')->getClientOriginalName());
|
||||||
|
|
||||||
|
// quiz level settings
|
||||||
|
Session::put('total_soal_per_level', $totalSoalPeLevel);
|
||||||
|
Session::put('jumlah_soal_per_level', $jumlahSoalPerLevel);
|
||||||
|
Session::put('level_awal', $request->level_awal);
|
||||||
|
Session::put('batas_naik_level', $batasNaikLevel);
|
||||||
|
Session::put('skor_level', $skorLevel);
|
||||||
|
Session::put('kkm', $request->kkm);
|
||||||
|
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function removeSession()
|
||||||
|
{
|
||||||
|
session()->forget('judul');
|
||||||
|
session()->forget('deskripsi');
|
||||||
|
session()->forget('matapelajaran_id');
|
||||||
|
session()->forget('waktu');
|
||||||
|
session()->forget('preview_soal');
|
||||||
|
session()->forget('total_soal');
|
||||||
|
session()->forget('total_soal_tampil');
|
||||||
|
session()->forget('uploaded_filename');
|
||||||
|
|
||||||
|
// quiz level settings
|
||||||
|
session()->forget('total_soal_per_level');
|
||||||
|
session()->forget('jumlah_soal_per_level');
|
||||||
|
session()->forget('level_awal');
|
||||||
|
session()->forget('batas_naik_level');
|
||||||
|
session()->forget('skor_level');
|
||||||
|
session()->forget('kkm');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetPreview()
|
||||||
|
{
|
||||||
|
$this->removeSession();
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', 'Data preview berhasil direset.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$nip = Auth::user()->guru->nip;
|
||||||
|
$matpel = MataPelajaran::where("guru_nip", $nip)->get();
|
||||||
|
$naik_level = json_encode(session('batas_naik_level') ?? []);
|
||||||
|
return view("pages.role_guru.quiz.create", compact(['matpel', 'naik_level']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$preview = session('preview_soal');
|
||||||
|
if (!is_array($preview)) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error',
|
||||||
|
'message' => 'Data soal tidak ditemukan atau session sudah habis. Silakan ulangi proses import/preview quiz.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
array_shift($preview);
|
||||||
|
|
||||||
|
if (!$preview || count($preview) <= 1) {
|
||||||
|
\Log::error('Quiz Import Error: Tidak ada data untuk disimpan');
|
||||||
|
Alert::error("Terjadi Kesalahan", "Tidak ada data untuk disimpan.");
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->total_soal_tampil < 10) {
|
||||||
|
\Log::error('Quiz Import Error: Jumlah soal minimal 10');
|
||||||
|
Alert::error("Terjadi Kesalahan", "Jumlah soal minimal 10.");
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// VALIDASI KETAT UNTUK MENCEGAH BUG QUIZ
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// 1. VALIDASI: Total soal per level harus sama dengan total soal tampil
|
||||||
|
$totalSoalPerLevel = 0;
|
||||||
|
foreach ($request->jumlah_soal_per_level as $key => $value) {
|
||||||
|
$totalSoalPerLevel += (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($totalSoalPerLevel != $request->total_soal_tampil) {
|
||||||
|
\Log::error('Quiz Import Error: Total soal per level tidak sama dengan total soal tampil');
|
||||||
|
\Log::error('Detail: Total soal per level = ' . $totalSoalPerLevel . ', Total soal tampil = ' . $request->total_soal_tampil);
|
||||||
|
\Log::error('Detail per level: ' . json_encode($request->jumlah_soal_per_level));
|
||||||
|
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Total soal per level ($totalSoalPerLevel) harus sama dengan total soal tampil ({$request->total_soal_tampil}).<br><br><strong>POTENSI BUG:</strong> Jika tidak sama, siswa bisa stuck di level tertentu karena soal tidak cukup.<br><strong>CATATAN:</strong> Pastikan jumlah soal per level dijumlahkan sama dengan total soal tampil."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. VALIDASI: Hitung jumlah soal yang tersedia per level dari data import
|
||||||
|
$levelCounts = [];
|
||||||
|
foreach ($preview as $row) {
|
||||||
|
if (!empty($row[3])) { // level
|
||||||
|
$level = $row[3];
|
||||||
|
$levelCounts[$level] = ($levelCounts[$level] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. VALIDASI: Jumlah soal per level tidak boleh melebihi soal yang tersedia
|
||||||
|
foreach ($request->jumlah_soal_per_level as $key => $value) {
|
||||||
|
$level = str_replace('level', '', $key);
|
||||||
|
$availableInLevel = $levelCounts[$level] ?? 0;
|
||||||
|
|
||||||
|
if ($value > $availableInLevel) {
|
||||||
|
\Log::error('Quiz Import Error: Jumlah soal setting melebihi soal yang tersedia');
|
||||||
|
\Log::error('Detail: Level ' . $level . ' - Setting: ' . $value . ', Tersedia: ' . $availableInLevel);
|
||||||
|
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level $level: Setting $value soal, tapi hanya ada $availableInLevel soal tersedia.<br><br><strong>POTENSI BUG:</strong> Sistem akan stuck karena tidak ada cukup soal di level tersebut.<br><strong>CATATAN:</strong> Kurangi jumlah soal setting atau tambah soal di level tersebut."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. VALIDASI: Batas naik level tidak boleh melebihi jumlah soal di level tersebut
|
||||||
|
foreach ($request->batas_naik_level as $key => $value) {
|
||||||
|
$level = str_replace('fase', '', $key);
|
||||||
|
$soalInLevel = $request->jumlah_soal_per_level["level$level"] ?? 0;
|
||||||
|
|
||||||
|
// VALIDASI BARU: Batas naik level tidak boleh sama atau lebih besar dari jumlah soal di level
|
||||||
|
if ($value >= $soalInLevel) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level $level: Syarat naik level ($value) tidak boleh sama atau lebih besar dari jumlah soal ($soalInLevel).<br><br><strong>POTENSI BUG:</strong> Jika siswa salah satu saja, quiz akan stuck di level ini.<br><strong>CATATAN:</strong> Kurangi syarat naik level atau tambah jumlah soal di level ini."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value > $soalInLevel) {
|
||||||
|
\Log::error('Quiz Import Error: Batas naik level melebihi jumlah soal di level');
|
||||||
|
\Log::error('Detail: Level ' . $level . ' - Batas naik: ' . $value . ', Soal di level: ' . $soalInLevel);
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level $level: Batas naik level ($value) tidak boleh melebihi jumlah soal ($soalInLevel).<br><br><strong>POTENSI BUG:</strong> Siswa tidak akan pernah naik level karena batas terlalu tinggi.<br><strong>CATATAN:</strong> Batas naik level harus ≤ jumlah soal di level tersebut."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. VALIDASI: Pastikan ada soal di setiap level yang di-setting
|
||||||
|
foreach ($request->jumlah_soal_per_level as $key => $value) {
|
||||||
|
$level = str_replace('level', '', $key);
|
||||||
|
$availableInLevel = $levelCounts[$level] ?? 0;
|
||||||
|
|
||||||
|
if ($availableInLevel == 0) {
|
||||||
|
\Log::error('Quiz Import Error: Tidak ada soal di level yang di-setting');
|
||||||
|
\Log::error('Detail: Level ' . $level . ' tidak memiliki soal di data import');
|
||||||
|
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level $level: Tidak ada soal tersedia di level ini.<br><br><strong>POTENSI BUG:</strong> Sistem akan stuck karena tidak ada soal di level tersebut.<br><strong>CATATAN:</strong> Pastikan data import memiliki soal dengan level $level atau hapus setting level ini."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. VALIDASI: Level harus berurutan (1, 2, 3, dst)
|
||||||
|
$levels = array_keys($request->jumlah_soal_per_level);
|
||||||
|
sort($levels);
|
||||||
|
$expectedLevels = [];
|
||||||
|
for ($i = 1; $i <= count($levels); $i++) {
|
||||||
|
$expectedLevels[] = "level$i";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($levels !== $expectedLevels) {
|
||||||
|
\Log::error('Quiz Import Error: Level tidak berurutan');
|
||||||
|
\Log::error('Detail: Level yang ada = ' . json_encode($levels) . ', Level yang diharapkan = ' . json_encode($expectedLevels));
|
||||||
|
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level harus berurutan (Level 1, Level 2, Level 3, dst).<br><br><strong>POTENSI BUG:</strong> Sistem adaptive learning akan bingung dengan level yang tidak berurutan.<br><strong>CATATAN:</strong> Pastikan level di data import berurutan dari 1, 2, 3, dst."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update session dengan nilai total_soal_tampil yang baru
|
||||||
|
Session::put('total_soal_tampil', $request->total_soal_tampil);
|
||||||
|
|
||||||
|
// VALIDASI: Jumlah soal yang harus dikerjakan per level tidak boleh melebihi jumlah soal di bank soal
|
||||||
|
$totalSoalPerLevel = 0;
|
||||||
|
foreach ($request->jumlah_soal_per_level as $key => $value) {
|
||||||
|
$level = str_replace('level', '', $key);
|
||||||
|
$soalTersedia = $request->total_soal_per_level["level$level"] ?? 0;
|
||||||
|
if ($value > $soalTersedia) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level $level: Jumlah soal yang dikerjakan ($value) tidak boleh lebih besar dari jumlah soal di bank soal ($soalTersedia)."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$totalSoalPerLevel += (int) $value;
|
||||||
|
}
|
||||||
|
// VALIDASI: Total soal yang harus dikerjakan (semua level) harus sama dengan total soal tampil
|
||||||
|
if ($totalSoalPerLevel != $request->total_soal_tampil) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Total soal yang harus dikerjakan ($totalSoalPerLevel) tidak sama dengan total soal tampil ({$request->total_soal_tampil}).<br><br><strong>POTENSI BUG:</strong> Quiz bisa stuck atau soal tidak cukup.<br><strong>CATATAN:</strong> Sesuaikan jumlah soal per level agar totalnya sama dengan total soal tampil."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// VALIDASI: Cegah quiz stuck jika syarat naik level tidak tercapai dan soal habis
|
||||||
|
foreach ($request->batas_naik_level as $key => $value) {
|
||||||
|
$level = str_replace('fase', '', $key);
|
||||||
|
$jumlah_soal = $request->jumlah_soal_per_level["level$level"] ?? 0;
|
||||||
|
$batas_naik = $value;
|
||||||
|
// Jika syarat naik lebih besar dari jumlah soal, mustahil
|
||||||
|
if ($batas_naik > $jumlah_soal) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Error Validasi',
|
||||||
|
'message' => "Level $level: Syarat naik level ($batas_naik) tidak boleh lebih besar dari jumlah soal yang dikerjakan ($jumlah_soal)."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// Jika syarat naik level terlalu rendah, tetap valid, tapi cek kemungkinan stuck
|
||||||
|
// Simulasi: Jika siswa menjawab semua soal tapi benar kurang dari syarat naik, quiz stuck
|
||||||
|
// Contoh: syarat naik 3 dari 10, jika siswa hanya benar 2, quiz stuck
|
||||||
|
// Validasi: syarat naik level harus bisa dicapai dengan minimal 1 benar di setiap soal
|
||||||
|
// (tidak perlu, karena sudah dicegah oleh logika di atas)
|
||||||
|
// Namun, jika syarat naik terlalu rendah, warning saja (tidak error)
|
||||||
|
// Jika syarat naik terlalu tinggi, error
|
||||||
|
// Jika syarat naik level tidak tercapai dan soal habis, quiz stuck
|
||||||
|
// (Sudah dicegah oleh validasi di atas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VALIDASI: Cegah quiz stuck jika siswa gagal naik level dan soal habis
|
||||||
|
/*
|
||||||
|
$levelKeys = array_keys($request->jumlah_soal_per_level);
|
||||||
|
$levelCount = count($levelKeys);
|
||||||
|
for ($i = 0; $i < $levelCount - 1; $i++) { // Kecuali level terakhir
|
||||||
|
$currentLevelKey = $levelKeys[$i];
|
||||||
|
$nextLevelKeys = array_slice($levelKeys, $i + 1);
|
||||||
|
$soalDiLevelIni = (int) $request->jumlah_soal_per_level[$currentLevelKey];
|
||||||
|
$soalDiLevelBerikutnya = 0;
|
||||||
|
foreach ($nextLevelKeys as $k) {
|
||||||
|
$soalDiLevelBerikutnya += (int) $request->jumlah_soal_per_level[$k];
|
||||||
|
}
|
||||||
|
$totalSoalTampil = (int) $request->total_soal_tampil;
|
||||||
|
$batasNaik = (int) ($request->batas_naik_level['fase' . ($i + 1)] ?? 0);
|
||||||
|
// Jika semua soal di level ini habis, dan siswa gagal naik (benar < batas naik), quiz stuck
|
||||||
|
// Kondisi: soal di level ini = total soal tampil - soal di level berikutnya
|
||||||
|
if ($soalDiLevelIni === $totalSoalTampil - $soalDiLevelBerikutnya && $soalDiLevelIni > 0 && $batasNaik > 0) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Konfigurasi Quiz Tidak Valid',
|
||||||
|
'message' => "Quiz tidak bisa disimpan karena pada fase " . ($i + 1) . ", siswa yang gagal naik ke level berikutnya akan kehabisan soal. Mohon ulangi konfigurasi quiz agar lebih seimbang dan baik."
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Simpan quiz dan soalnya ke DB
|
||||||
|
$quiz = Quizzes::create([
|
||||||
|
'judul' => $request->judul,
|
||||||
|
'deskripsi' => $request->deskripsi,
|
||||||
|
'matapelajaran_id' => $request->matapelajaran_id,
|
||||||
|
'total_soal' => $request->total_soal,
|
||||||
|
'total_soal_tampil' => $request->total_soal_tampil,
|
||||||
|
'waktu' => $request->waktu,
|
||||||
|
]);
|
||||||
|
|
||||||
|
QuizLevelSetting::create([
|
||||||
|
'quiz_id' => $quiz->id,
|
||||||
|
'jumlah_soal_per_level' => json_encode($request->jumlah_soal_per_level),
|
||||||
|
'level_awal' => session('level_awal') ?? 1,
|
||||||
|
'batas_naik_level' => json_encode($request->batas_naik_level),
|
||||||
|
'skor_level' => json_encode(session('skor_level')),
|
||||||
|
'kkm' => session('kkm') ?? 75,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Menampung data dalam array sebelum disimpan
|
||||||
|
$quizQuestionsData = [];
|
||||||
|
|
||||||
|
foreach ($preview as $row) {
|
||||||
|
$jawabanBenar = strtolower(trim($row[2]));
|
||||||
|
// Menyiapkan data untuk disimpan
|
||||||
|
$quizQuestionsData[] = [
|
||||||
|
'quiz_id' => $quiz->id,
|
||||||
|
'pertanyaan' => $row[1],
|
||||||
|
'opsi_a' => $row[4],
|
||||||
|
'opsi_b' => $row[5],
|
||||||
|
'opsi_c' => $row[6],
|
||||||
|
'opsi_d' => $row[7],
|
||||||
|
'jawaban_benar' => $jawabanBenar,
|
||||||
|
'level' => $row[3],
|
||||||
|
'skor' => $row[8],
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan semua data sekali gus menggunakan insert
|
||||||
|
if (!empty($quizQuestionsData)) {
|
||||||
|
QuizQuestions::insert($quizQuestionsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hapus session
|
||||||
|
$this->removeSession();
|
||||||
|
|
||||||
|
$matpel = MataPelajaran::findOrFail($request->matapelajaran_id);
|
||||||
|
// Cari siswa berdasarkan kelas dan tahun ajaran
|
||||||
|
$siswas = Siswa::where('kelas', $matpel['kelas'])
|
||||||
|
->where('tahun_ajaran', $matpel['tahun_ajaran'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Kirim notifikasi ke setiap siswa
|
||||||
|
foreach ($siswas as $siswa) {
|
||||||
|
$siswa->notify(new QuizBaruNotification($quiz));
|
||||||
|
}
|
||||||
|
|
||||||
|
\Log::info('Quiz berhasil diimport: ' . $request->judul);
|
||||||
|
return redirect()->route('quiz')->with('success_message', [
|
||||||
|
'title' => 'Berhasil',
|
||||||
|
'message' => 'Data quiz berhasil disimpan dan notifikasi telah dikirim ke siswa.'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::error('Quiz Import Error: ' . $e->getMessage());
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Terjadi Kesalahan',
|
||||||
|
'message' => 'Gagal menyimpan data quiz: ' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
} catch (\Illuminate\Database\QueryException $e) {
|
||||||
|
\Log::error('Quiz Import Error: Database error - ' . $e->getMessage());
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Terjadi Kesalahan',
|
||||||
|
'message' => 'Gagal menyimpan data quiz. Silakan coba lagi.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$quiz = Quizzes::findOrFail($request->formid);
|
||||||
|
$quiz->delete();
|
||||||
|
return redirect()->back()->with('success_message', [
|
||||||
|
'title' => 'Berhasil',
|
||||||
|
'message' => 'Data quiz berhasil dihapus.'
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return redirect()->back()->with('validation_error', [
|
||||||
|
'title' => 'Terjadi Kesalahan',
|
||||||
|
'message' => 'Gagal menghapus data quiz: ' . $th->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\RoleGuru;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\QuizAttempts;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class QuizRankingController extends Controller
|
||||||
|
{
|
||||||
|
// GET /quiz/{quizId}/ranking
|
||||||
|
public function ranking($quizId)
|
||||||
|
{
|
||||||
|
// Ambil attempt terbaru per siswa untuk quiz ini
|
||||||
|
$latestAttempts = QuizAttempts::where('quiz_id', $quizId)
|
||||||
|
->selectRaw('MAX(id) as id')
|
||||||
|
->groupBy('nisn')
|
||||||
|
->pluck('id');
|
||||||
|
|
||||||
|
$ranking = QuizAttempts::with('siswa')
|
||||||
|
->whereIn('id', $latestAttempts)
|
||||||
|
->get()
|
||||||
|
->map(function($attempt) {
|
||||||
|
return [
|
||||||
|
'nama' => $attempt->siswa->nama ?? '-',
|
||||||
|
'nisn' => $attempt->nisn,
|
||||||
|
'skor' => (int) $attempt->skor,
|
||||||
|
'waktu_selesai' => $attempt->updated_at,
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->sortByDesc('skor')
|
||||||
|
->values()
|
||||||
|
->take(5);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'ranking' => $ranking
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /quiz/{quizId}/skor-saya
|
||||||
|
public function skorSaya($quizId)
|
||||||
|
{
|
||||||
|
$nisn = auth()->user()->siswa->nisn ?? null;
|
||||||
|
if (!$nisn) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'User bukan siswa.']);
|
||||||
|
}
|
||||||
|
$attempt = QuizAttempts::where('quiz_id', $quizId)
|
||||||
|
->where('nisn', $nisn)
|
||||||
|
->orderByDesc('id')
|
||||||
|
->first();
|
||||||
|
if (!$attempt) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Belum ada attempt.']);
|
||||||
|
}
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'skor' => $attempt->skor,
|
||||||
|
'waktu_selesai' => $attempt->updated_at,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\RoleGuru;
|
||||||
|
|
||||||
|
use App\Exports\RekapExport;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\QuizAttempts;
|
||||||
|
use App\Models\QuizLevelSetting;
|
||||||
|
use App\Models\Quizzes;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
|
|
||||||
|
class RekapQuizController extends Controller
|
||||||
|
{
|
||||||
|
static function getNilai($first)
|
||||||
|
{
|
||||||
|
$quizId = $first->quiz_id;
|
||||||
|
$quizLevelSettings = QuizLevelSetting::where('quiz_id', $quizId)->first();
|
||||||
|
$jumlahSoalPerLevel = json_decode($quizLevelSettings->jumlah_soal_per_level, true);
|
||||||
|
$totalSkorLevel = 0;
|
||||||
|
|
||||||
|
foreach (json_decode($quizLevelSettings->skor_level) as $key => $value) {
|
||||||
|
$totalSkorLevel += $value * (int) $jumlahSoalPerLevel[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
"total_skor_level" => $totalSkorLevel,
|
||||||
|
"kkm" => $quizLevelSettings->kkm,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$nip = Auth::user()->guru->nip;
|
||||||
|
$matpel = MataPelajaran::where('guru_nip', $nip)->get();
|
||||||
|
$judulQuiz = Quizzes::where('judul', $request->judul)->first();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
|
||||||
|
$query = QuizAttempts::with(['quizzes', 'siswa'])
|
||||||
|
->whereHas('quizzes', function ($q) use ($request) {
|
||||||
|
$q->where('judul', $request->judul);
|
||||||
|
})->whereHas('siswa', function ($q) use ($request) {
|
||||||
|
$q->where('kelas', $request->kelas)
|
||||||
|
->where('tahun_ajaran', $request->tahun_ajaran);
|
||||||
|
})->get();
|
||||||
|
|
||||||
|
$rekap = $query->map(function ($item) use ($request) {
|
||||||
|
$nilaiData = $this->getNilai($item);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'matapelajaran' => $item->quizzes->mataPelajaran->nama,
|
||||||
|
'judul_quiz' => $item->quizzes->judul,
|
||||||
|
'nama_siswa' => $item->siswa->nama,
|
||||||
|
'tahun_ajaran' => $request->tahun_ajaran,
|
||||||
|
'kelas' => $request->kelas,
|
||||||
|
'mapel_id' => $item->quizzes->mataPelajaran->id,
|
||||||
|
'total_skor' => $item->skor,
|
||||||
|
'persentase' => round(($item->skor / $nilaiData['total_skor_level']) * 100),
|
||||||
|
'kkm' => $nilaiData['kkm'],
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($request->input('action') === 'download') {
|
||||||
|
return Excel::download(new RekapExport($rekap), 'rekap-quiz' . $request->kelas . '.xlsx');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert $rekap to array to prevent automatic JSON conversion
|
||||||
|
$rekapArray = $rekap->toArray();
|
||||||
|
return view("pages.role_guru.quiz.rekap-quiz", compact(['matpel', 'judulQuiz', 'kelas', 'tahunAjaran', 'rekapArray']));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\RoleGuru;
|
||||||
|
|
||||||
|
use App\Exports\TugasDetailExport;
|
||||||
|
use App\Exports\TugasExport;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\SubmitTugas;
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class RekapTugasController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$guruNip = Auth::user()->guru->nip;
|
||||||
|
|
||||||
|
// Get mata pelajaran yang diajar oleh guru
|
||||||
|
$mataPelajaran = MataPelajaran::where('guru_nip', $guruNip)->get();
|
||||||
|
|
||||||
|
// Get kelas yang diajar oleh guru
|
||||||
|
$kelasList = Kelas::whereIn('nama', $mataPelajaran->pluck('kelas'))->get();
|
||||||
|
|
||||||
|
// Filter parameters
|
||||||
|
$selectedKelas = $request->get('kelas');
|
||||||
|
$selectedMatpel = $request->get('matpel');
|
||||||
|
$search = $request->get('search');
|
||||||
|
|
||||||
|
// Query untuk mendapatkan tugas yang dibuat oleh guru
|
||||||
|
$query = Tugas::with(['mataPelajaran', 'submitTugas.siswa'])
|
||||||
|
->where('guru_nip', $guruNip);
|
||||||
|
|
||||||
|
// Apply filters
|
||||||
|
if ($selectedKelas) {
|
||||||
|
$query->where('kelas', $selectedKelas);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($selectedMatpel) {
|
||||||
|
$query->where('matapelajaran_id', $selectedMatpel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($search) {
|
||||||
|
$query->where('nama', 'like', '%' . $search . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tugas = $query->orderBy('created_at', 'desc')->paginate(10);
|
||||||
|
|
||||||
|
// Ensure submitTugas is always a collection
|
||||||
|
$tugas->getCollection()->transform(function ($t) {
|
||||||
|
if (!$t->submitTugas) {
|
||||||
|
$t->setRelation('submitTugas', collect());
|
||||||
|
}
|
||||||
|
return $t;
|
||||||
|
});
|
||||||
|
|
||||||
|
return view('pages.role_guru.rekap_tugas.index', compact(
|
||||||
|
'tugas',
|
||||||
|
'kelasList',
|
||||||
|
'mataPelajaran',
|
||||||
|
'selectedKelas',
|
||||||
|
'selectedMatpel',
|
||||||
|
'search'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail($id)
|
||||||
|
{
|
||||||
|
$tugas = Tugas::with(['mataPelajaran', 'submitTugas.siswa'])
|
||||||
|
->where('guru_nip', Auth::user()->guru->nip)
|
||||||
|
->findOrFail($id);
|
||||||
|
|
||||||
|
$submitTugas = SubmitTugas::with('siswa')
|
||||||
|
->where('tugas_id', $id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('pages.role_guru.rekap_tugas.detail', compact('tugas', 'submitTugas'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateNilai(Request $request, $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request->validate([
|
||||||
|
'nilai' => 'required|numeric|min:0|max:100'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$submitTugas = SubmitTugas::findOrFail($id);
|
||||||
|
|
||||||
|
// Check if the task belongs to the teacher
|
||||||
|
$tugas = Tugas::where('id', $submitTugas->tugas_id)
|
||||||
|
->where('guru_nip', Auth::user()->guru->nip)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$tugas) {
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Anda tidak memiliki akses untuk menilai tugas ini.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
Alert::error("Error", "Anda tidak memiliki akses untuk menilai tugas ini.");
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$submitTugas->update([
|
||||||
|
'nilai' => $request->nilai
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Nilai berhasil diperbarui.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert::success("Berhasil", "Nilai berhasil diperbarui.");
|
||||||
|
return back();
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Terjadi kesalahan: ' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert::error("Error", "Terjadi kesalahan: " . $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export(Request $request)
|
||||||
|
{
|
||||||
|
$selectedKelas = $request->get('kelas');
|
||||||
|
$selectedMatpel = $request->get('matpel');
|
||||||
|
|
||||||
|
$filename = 'rekap_tugas_' . date('Y-m-d_H-i-s') . '.xlsx';
|
||||||
|
|
||||||
|
return Excel::download(
|
||||||
|
new TugasExport($selectedKelas, $selectedMatpel),
|
||||||
|
$filename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportDetail(Request $request)
|
||||||
|
{
|
||||||
|
$selectedKelas = $request->get('kelas');
|
||||||
|
$selectedMatpel = $request->get('matpel');
|
||||||
|
|
||||||
|
$filename = 'detail_tugas_' . date('Y-m-d_H-i-s') . '.xlsx';
|
||||||
|
|
||||||
|
return Excel::download(
|
||||||
|
new TugasDetailExport($selectedKelas, $selectedMatpel),
|
||||||
|
$filename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\RoleGuru;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use App\Repositories\TugasRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class TugasController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(TugasRepository $tugas)
|
||||||
|
{
|
||||||
|
$this->param = $tugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dateFormat($date)
|
||||||
|
{
|
||||||
|
return date('Y-m-d H:i:s', strtotime($date));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataRequirement()
|
||||||
|
{
|
||||||
|
$mataPelajaran = MataPelajaran::where('guru_nip', Auth::user()->guru->nip)->get();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
|
||||||
|
return [$mataPelajaran, $kelas, $tahunAjaran];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$tugas = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_guru.tugas.index", compact("tugas"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$mataPelajaran = MataPelajaran::where('guru_nip', Auth::user()->guru->nip)->get();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
return view("pages.role_guru.tugas.create", compact(["mataPelajaran", "kelas", "tahunAjaran"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request['tanggal'] = $this->dateFormat($request->input('tanggal'));
|
||||||
|
$request['tenggat'] = $this->dateFormat($request->input('tenggat'));
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'tanggal' => 'required',
|
||||||
|
'tenggat' => 'required',
|
||||||
|
'nama' => 'required',
|
||||||
|
'matapelajaran_id' => 'required',
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
'deskripsi' => 'nullable|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di simpan.");
|
||||||
|
return redirect()->route("tugas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$tugas = $this->param->find($id);
|
||||||
|
$mataPelajaran = MataPelajaran::where('guru_nip', Auth::user()->guru->nip)->get();
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
return view("pages.role_guru.tugas.edit", compact(["tugas", "mataPelajaran", "kelas", "tahunAjaran"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request['tanggal'] = $this->dateFormat($request->input('tanggal'));
|
||||||
|
$request['tenggat'] = $this->dateFormat($request->input('tenggat'));
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'tanggal' => 'required',
|
||||||
|
'tenggat' => 'required',
|
||||||
|
'nama' => 'required',
|
||||||
|
'matapelajaran_id' => 'required',
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
'deskripsi' => 'nullable|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->update($data, $id);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di ubah.");
|
||||||
|
return redirect()->route("tugas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->param->destroy($request->formid);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di hapus.");
|
||||||
|
return redirect()->route("tugas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Repositories\SiswaRepository;
|
||||||
|
use App\Repositories\UserRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class SiswaController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
protected $paramUser;
|
||||||
|
|
||||||
|
public function __construct(SiswaRepository $siswa, UserRepository $user)
|
||||||
|
{
|
||||||
|
$this->param = $siswa;
|
||||||
|
$this->paramUser = $user;
|
||||||
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$siswa = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_admin.siswa.index", compact("siswa"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$kelas = Kelas::get();
|
||||||
|
$tahunAjaran = TahunAjaran::get();
|
||||||
|
return view("pages.role_admin.siswa.create", compact("kelas", 'tahunAjaran'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$dataUser = $request->validate([
|
||||||
|
'email' => 'required',
|
||||||
|
'role' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'nisn' => 'required|string|size:10|unique:siswa,nisn',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'jk' => 'required',
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (Siswa::where('nisn', $data['nisn'])->exists()) {
|
||||||
|
Alert::error("Terjadi Kesalahan", "NISN sudah terdaftar.");
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataUser['pass'] = $request->nisn;
|
||||||
|
$user = $this->paramUser->store($dataUser);
|
||||||
|
|
||||||
|
$data["user_id"] = $user->id;
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di simpan.");
|
||||||
|
return redirect()->route("siswa");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$kelas = Kelas::get();
|
||||||
|
$tahunAjaran = TahunAjaran::get();
|
||||||
|
$siswa = Siswa::find($id);
|
||||||
|
return view("pages.role_admin.siswa.edit", compact(["kelas", "siswa", "tahunAjaran"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$dataUser = $request->validate([
|
||||||
|
'email' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'nisn' => 'required|string|size:10',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'jk' => 'required',
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->paramUser->update($dataUser, $request->user_id);
|
||||||
|
$this->param->update($data, $id);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di ubah.");
|
||||||
|
return redirect()->route("siswa");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->param->destroy($request->formid);
|
||||||
|
$this->paramUser->destroy($request->user_id);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Hapus.");
|
||||||
|
return redirect()->route("siswa");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class SiswaNotifikasiController extends Controller
|
||||||
|
{
|
||||||
|
public function notifCount(Request $request)
|
||||||
|
{
|
||||||
|
$siswa = $request->user()->siswa;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'unread_count' => $siswa->unreadNotifications->count(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$siswa = $request->user()->siswa;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'notifications' => $siswa->notifications->map(function ($notif) {
|
||||||
|
return [
|
||||||
|
'id' => $notif->id,
|
||||||
|
'type' => $notif->data['type'],
|
||||||
|
'judul' => $notif->data['judul'] ?? '-',
|
||||||
|
'tenggat' => $notif->data['tenggat'] ?? null,
|
||||||
|
'matapelajaran_id' => $notif->data['matapelajaran_id'] ?? null,
|
||||||
|
'matapelajaran_nama' => $notif->data['matapelajaran_nama'] ?? null,
|
||||||
|
'tugas_id' => $notif->data['tugas_id'] ?? null,
|
||||||
|
'quiz_id' => $notif->data['quiz_id'] ?? null,
|
||||||
|
'read_at' => $notif->read_at,
|
||||||
|
'created_at' => $notif->created_at->toDateTimeString(),
|
||||||
|
'is_active' => $notif->read_at == null,
|
||||||
|
];
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tandai notifikasi sebagai sudah dibaca
|
||||||
|
public function markAsRead(Request $request, $id)
|
||||||
|
{
|
||||||
|
$notif = $request->user()->siswa->notifications()->findOrFail($id);
|
||||||
|
$notif->markAsRead();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Notifikasi ditandai sebagai dibaca.',
|
||||||
|
'id' => $id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Repositories\TahunAjaranRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class TahunAjaranController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(TahunAjaranRepository $tahunAjaran)
|
||||||
|
{
|
||||||
|
$this->param = $tahunAjaran;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$tahunAjaran = $this->param->getData($search, $limit);
|
||||||
|
return view("pages.role_admin.tahun_ajaran.index", compact("tahunAjaran"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
return view("pages.role_admin.tahun_ajaran.create");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'tahun' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->store($data);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Tambahkan.");
|
||||||
|
return redirect()->route("tahun-ajaran");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(Request $request)
|
||||||
|
{
|
||||||
|
$tahun = urldecode($request->tahun_ajaran);
|
||||||
|
$tahunAjaran = TahunAjaran::where('tahun', $tahun)->firstOrFail();
|
||||||
|
return view('pages.role_admin.tahun_ajaran.edit', compact('tahunAjaran'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$tahun = urldecode($request->tahun_ajaran);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'status' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->update($data, $tahun);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Ubah.");
|
||||||
|
return redirect()->route("tahun-ajaran");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$tahun = $request->input('tahun');
|
||||||
|
$this->param->destroy($tahun);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Hapus.");
|
||||||
|
return redirect()->route("tahun-ajaran");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Traits;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
trait ApiResponse
|
||||||
|
{
|
||||||
|
protected function okApiResponse($data, $message = 'Success'): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'status' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $data
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response error (400/500 Internal Server Error)
|
||||||
|
*/
|
||||||
|
protected function errorApiResponse($message = 'Something went wrong', $statusCode = 500): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'status' => false,
|
||||||
|
'message' => $message,
|
||||||
|
], $statusCode);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class UserController extends Controller
|
||||||
|
{
|
||||||
|
public function change()
|
||||||
|
{
|
||||||
|
return view("pages.auth.change_password");
|
||||||
|
}
|
||||||
|
public function changePassword(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request->validate([
|
||||||
|
'old_password' => ['required'],
|
||||||
|
'new_password' => ['required', 'min:8', 'confirmed'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if (!Hash::check($request->old_password, $user->password)) {
|
||||||
|
Alert::error("Terjadi Kesalahan", "Password lama salah.");
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
User::where('id', $user->id)->update(['password' => Hash::make($request->new_password)]);
|
||||||
|
Alert::success('Berhasil', 'Password berhasil diubah.');
|
||||||
|
if ($user->role == "guru") {
|
||||||
|
return redirect()->route("dashboard.guru");
|
||||||
|
} else {
|
||||||
|
return redirect()->route("/");
|
||||||
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Alert::error($th->getMessage());
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changePasswordApi(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request->validate([
|
||||||
|
'old_password' => ['required'],
|
||||||
|
'new_password' => ['required', 'min:8', 'confirmed'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if (!Hash::check($request->old_password, $user->password)) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => false,
|
||||||
|
'message' => "Password lama salah.",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
User::where('id', $user->id)->update(['password' => Hash::make($request->new_password)]);
|
||||||
|
return response()->json([
|
||||||
|
'status' => true,
|
||||||
|
'message' => "Password berhasil diubah.",
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return response()->json([
|
||||||
|
"status" => false,
|
||||||
|
'message' => $th->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Guru;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Models\AuditLog;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use App\Repositories\WaliKelasRepository;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use RealRashid\SweetAlert\Facades\Alert;
|
||||||
|
|
||||||
|
class WaliKelasController extends Controller
|
||||||
|
{
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(WaliKelasRepository $waliKelas)
|
||||||
|
{
|
||||||
|
$this->param = $waliKelas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$limit = $request->has('page_length') ? $request->get('page_length') : 10;
|
||||||
|
$search = $request->has('search') ? $request->get('search') : null;
|
||||||
|
$waliKelas = $this->param->getData($search, $limit);
|
||||||
|
return view('pages.role_admin.wali_kelas.index', compact('waliKelas'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$kelas = Kelas::get();
|
||||||
|
$guru = Guru::get();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
return view('pages.role_admin.wali_kelas.create', compact(['kelas', 'guru', 'tahunAjaran']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
'wali_nip' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->store($data);
|
||||||
|
// Update kolom nip_wali pada tabel kelas
|
||||||
|
Kelas::where('nama', $data['kelas'])->update(['nip_wali' => $data['wali_nip']]);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di Tambahkan.");
|
||||||
|
return redirect()->route("wali-kelas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
$waliKelas = $this->param->find($id);
|
||||||
|
$kelas = Kelas::get();
|
||||||
|
$guru = Guru::get();
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->get();
|
||||||
|
return view('pages.role_admin.wali_kelas.edit', compact(['waliKelas', 'kelas', 'guru', 'tahunAjaran']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'kelas' => 'required',
|
||||||
|
'tahun_ajaran' => 'required',
|
||||||
|
'wali_nip' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->param->update($data, $id);
|
||||||
|
// Update kolom nip_wali pada tabel kelas
|
||||||
|
Kelas::where('nama', $data['kelas'])->update(['nip_wali' => $data['wali_nip']]);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di ubah.");
|
||||||
|
return redirect()->route("wali-kelas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back()->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$wali = $this->param->find($request->formid);
|
||||||
|
// Cek apakah wali kelas masih aktif di tabel kelas
|
||||||
|
$isWali = Kelas::where('nip_wali', $wali->wali_nip)->exists();
|
||||||
|
if ($isWali) {
|
||||||
|
Alert::error('Gagal', 'Tidak dapat menghapus wali kelas karena masih aktif di kelas. Silakan ganti wali kelas terlebih dahulu.');
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
$this->param->destroy($request->formid);
|
||||||
|
// Audit log
|
||||||
|
AuditLog::create([
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'action' => 'delete_wali_kelas',
|
||||||
|
'description' => 'Menghapus wali kelas: ' . $wali->wali_nip,
|
||||||
|
]);
|
||||||
|
Alert::success("Berhasil", "Data Berhasil di hapus.");
|
||||||
|
return redirect()->route("wali-kelas");
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::error("Terjadi Kesalahan", $e->getMessage());
|
||||||
|
return back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Laravel\Sanctum\PersonalAccessToken;
|
||||||
|
|
||||||
|
class CheckApiToken
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$header = $request->header('Authorization');
|
||||||
|
|
||||||
|
if (!$header || !str_starts_with($header, 'Bearer ')) {
|
||||||
|
return response()->json(['message' => 'Token tidak ditemukan.'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$accessToken = str_replace('Bearer ', '', $header);
|
||||||
|
|
||||||
|
$token = PersonalAccessToken::findToken($accessToken);
|
||||||
|
|
||||||
|
if (!$token) {
|
||||||
|
return response()->json(['message' => 'Token tidak valid.'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set user yang sedang login (penting)
|
||||||
|
$request->merge(['user' => $token->tokenable]);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class RoleMiddleware
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next, ...$roles): Response
|
||||||
|
{
|
||||||
|
if (!Auth::check()) {
|
||||||
|
return redirect('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if (in_array($user->role, $roles)) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403, 'Unauthorized');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class ChangePasswordRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'old_password' => ['required'],
|
||||||
|
'new_password' => ['required', 'min:8', 'confirmed'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class SubmitTugasResource extends JsonResource
|
||||||
|
{
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'tanggal' => $this->tanggal ? Carbon::parse($this->tanggal)->format('Y-m-d H:i:s') : null,
|
||||||
|
'nisn' => $this->nisn,
|
||||||
|
'tugas_id' => $this->tugas_id,
|
||||||
|
'text' => $this->text,
|
||||||
|
'file' => $this->file,
|
||||||
|
'nilai' => $this->nilai,
|
||||||
|
'created_at' => $this->created_at ? $this->created_at->format('Y-m-d H:i:s') : null,
|
||||||
|
'updated_at' => $this->updated_at ? $this->updated_at->format('Y-m-d H:i:s') : null,
|
||||||
|
'siswa' => $this->whenLoaded('siswa', function () {
|
||||||
|
return [
|
||||||
|
'nisn' => $this->siswa->nisn,
|
||||||
|
'nama' => $this->siswa->nama,
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class TugasResource extends JsonResource
|
||||||
|
{
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'nama' => $this->nama,
|
||||||
|
'deskripsi' => $this->deskripsi,
|
||||||
|
'tanggal' => $this->tanggal ? Carbon::parse($this->tanggal)->format('Y-m-d H:i:s') : null,
|
||||||
|
'tenggat' => $this->tenggat ? Carbon::parse($this->tenggat)->format('Y-m-d H:i:s') : null,
|
||||||
|
'guru_nip' => $this->guru_nip,
|
||||||
|
'matapelajaran_id' => $this->matapelajaran_id,
|
||||||
|
'kelas' => $this->kelas,
|
||||||
|
'tahun_ajaran' => $this->tahun_ajaran,
|
||||||
|
'mata_pelajaran' => $this->whenLoaded('mataPelajaran', function () {
|
||||||
|
return [
|
||||||
|
'id' => $this->mataPelajaran->id,
|
||||||
|
'nama' => $this->mataPelajaran->nama,
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
'submit_tugas' => SubmitTugasResource::collection($this->whenLoaded('submitTugas')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Imports;
|
||||||
|
|
||||||
|
use App\Models\QuizQuestions;
|
||||||
|
use Maatwebsite\Excel\Concerns\ToModel;
|
||||||
|
|
||||||
|
class QuizImport implements ToModel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array $row
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Model|null
|
||||||
|
*/
|
||||||
|
public function model(array $row)
|
||||||
|
{
|
||||||
|
return new QuizQuestions([
|
||||||
|
//
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Admin extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'admin';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'user_id',
|
||||||
|
'nip',
|
||||||
|
'nama',
|
||||||
|
'jk',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class AuditLog extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'audit_logs';
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id', 'action', 'description'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Guru extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'guru';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'user_id',
|
||||||
|
'nip',
|
||||||
|
'nama',
|
||||||
|
'jk',
|
||||||
|
];
|
||||||
|
|
||||||
|
// public function kelas()
|
||||||
|
// {
|
||||||
|
// return $this->hasOne(Kelas::class, 'nip_wali', 'nip');
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function mataPelajaran()
|
||||||
|
{
|
||||||
|
return $this->hasOne(MataPelajaran::class, 'guru_nip', 'nip');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Kelas extends Model
|
||||||
|
{
|
||||||
|
protected $table = "kelas";
|
||||||
|
protected $fillable = [
|
||||||
|
"nama",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function siswa()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Siswa::class, 'kelas', 'nama');
|
||||||
|
}
|
||||||
|
|
||||||
|
// public function guru()
|
||||||
|
// {
|
||||||
|
// return $this->belongsTo(Guru::class, 'nip_wali', 'nip');
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function mataPelajaran()
|
||||||
|
{
|
||||||
|
return $this->hasMany(MataPelajaran::class, 'kelas', 'nama');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class MataPelajaran extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'matapelajaran';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"nama",
|
||||||
|
"guru_nip",
|
||||||
|
"kelas",
|
||||||
|
"tahun_ajaran",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function materi()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Materi::class, "matapelajaran_id", "id");
|
||||||
|
}
|
||||||
|
public function guru()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Guru::class, "guru_nip", "nip");
|
||||||
|
}
|
||||||
|
public function kelas()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kelas::class, "kelas", "nama");
|
||||||
|
}
|
||||||
|
public function tahunAjaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(TahunAjaran::class, "tahun_ajaran", "tahun");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Materi extends Model
|
||||||
|
{
|
||||||
|
protected $table = "materi";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"tanggal",
|
||||||
|
"matapelajaran_id",
|
||||||
|
"semester",
|
||||||
|
"type",
|
||||||
|
"judul_materi",
|
||||||
|
"deskripsi",
|
||||||
|
"path",
|
||||||
|
"tahun_ajaran"
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mataPelajaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(MataPelajaran::class, "matapelajaran_id", "id");
|
||||||
|
}
|
||||||
|
public function tahunAjaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(TahunAjaran::class, "tahun_ajaran", "tahun");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class QuizAttemptAnswers extends Model
|
||||||
|
{
|
||||||
|
protected $table = "quiz_attempt_answers";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"attempt_id",
|
||||||
|
"question_id",
|
||||||
|
"jawaban_siswa",
|
||||||
|
"benar",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function quizAttempt()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(QuizAttempts::class, "attempt_id", "id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quizQuestion()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(QuizQuestions::class, "question_id", "id");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class QuizAttempts extends Model
|
||||||
|
{
|
||||||
|
protected $table = "quiz_attempts";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"quiz_id",
|
||||||
|
"nisn",
|
||||||
|
"skor",
|
||||||
|
"level_akhir",
|
||||||
|
"jumlah_soal_dijawab",
|
||||||
|
"benar",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function attemptAnswers()
|
||||||
|
{
|
||||||
|
return $this->hasMany(QuizAttemptAnswers::class, 'attempt_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jumlahJawaban()
|
||||||
|
{
|
||||||
|
return $this->hasMany(QuizAttemptAnswers::class, 'attempt_id')->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quizzes()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Quizzes::class, "quiz_id", "id");
|
||||||
|
}
|
||||||
|
public function siswa()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Siswa::class, "nisn", "nisn");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class QuizLevelSetting extends Model
|
||||||
|
{
|
||||||
|
protected $table = "quiz_level_settings";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'quiz_id',
|
||||||
|
'jumlah_soal_per_level',
|
||||||
|
'level_awal',
|
||||||
|
'batas_naik_level',
|
||||||
|
'skor_level',
|
||||||
|
'kkm',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function quiz()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Quizzes::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class QuizQuestions extends Model
|
||||||
|
{
|
||||||
|
protected $table = "quiz_questions";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"quiz_id",
|
||||||
|
"pertanyaan",
|
||||||
|
"opsi_a",
|
||||||
|
"opsi_b",
|
||||||
|
"opsi_c",
|
||||||
|
"opsi_d",
|
||||||
|
"jawaban_bener",
|
||||||
|
"level",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function attemptAnswers()
|
||||||
|
{
|
||||||
|
return $this->hasMany(QuizAttemptAnswers::class, 'question_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quiz()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Quizzes::class, "quiz_id", "id");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Quizzes extends Model
|
||||||
|
{
|
||||||
|
protected $table = "quizzes";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"judul",
|
||||||
|
"deskripsi",
|
||||||
|
"total_soal",
|
||||||
|
"total_soal_tampil",
|
||||||
|
"waktu",
|
||||||
|
"matapelajaran_id",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function levelSetting()
|
||||||
|
{
|
||||||
|
return $this->hasOne(QuizLevelSetting::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quizAttempt()
|
||||||
|
{
|
||||||
|
return $this->hasOne(QuizAttempts::class, "quiz_id", "id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quizLevelSetting()
|
||||||
|
{
|
||||||
|
return $this->hasOne(QuizLevelSetting::class, 'quiz_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mataPelajaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(MataPelajaran::class, "matapelajaran_id", "id");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
class Siswa extends Model
|
||||||
|
{
|
||||||
|
use Notifiable;
|
||||||
|
protected $table = "siswa";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"user_id",
|
||||||
|
"nisn",
|
||||||
|
"nama",
|
||||||
|
"jk",
|
||||||
|
"kelas",
|
||||||
|
"tahun_ajaran",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function submitTugas()
|
||||||
|
{
|
||||||
|
return $this->hasOne(SubmitTugas::class, "nisn", "nisn");
|
||||||
|
}
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, "user_id", "id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kelas()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kelas::class, "kelas", "nama");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tahunAjaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(TahunAjaran::class, "tahun_ajaran", "tahun");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SubmitTugas extends Model
|
||||||
|
{
|
||||||
|
protected $table = "submit_tugas";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"id",
|
||||||
|
"tanggal",
|
||||||
|
"nisn",
|
||||||
|
"tugas_id",
|
||||||
|
"text",
|
||||||
|
"file",
|
||||||
|
"nilai"
|
||||||
|
];
|
||||||
|
|
||||||
|
public function siswa()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Siswa::class, "nisn", "nisn");
|
||||||
|
}
|
||||||
|
public function tugas()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Tugas::class, "tugas_id", "id");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TahunAjaran extends Model
|
||||||
|
{
|
||||||
|
protected $table = "tahun_ajaran";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"tahun",
|
||||||
|
"status",
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Tugas extends Model
|
||||||
|
{
|
||||||
|
protected $table = "tugas";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"tanggal",
|
||||||
|
"tenggat",
|
||||||
|
"guru_nip",
|
||||||
|
"nama",
|
||||||
|
"matapelajaran_id",
|
||||||
|
"kelas",
|
||||||
|
"tahun_ajaran",
|
||||||
|
'deskripsi',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function submitTugas()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SubmitTugas::class, "tugas_id", "id");
|
||||||
|
}
|
||||||
|
public function guru()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Guru::class, "guru_nip", "nip");
|
||||||
|
}
|
||||||
|
public function mataPelajaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(MataPelajaran::class, "matapelajaran_id", "id");
|
||||||
|
}
|
||||||
|
public function tahunAjaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(TahunAjaran::class, "tahun_ajaran", "id");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
|
||||||
|
class User extends Authenticatable
|
||||||
|
{
|
||||||
|
use HasFactory, Notifiable, HasApiTokens;
|
||||||
|
|
||||||
|
protected $table = 'users';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
'role',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'password' => 'hashed',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function admin()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Admin::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function guru()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Guru::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function siswa()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Siswa::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class WaliKelas extends Model
|
||||||
|
{
|
||||||
|
protected $table = "riwayat_kelas";
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"kelas",
|
||||||
|
"tahun_ajaran",
|
||||||
|
"wali_nip",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function kelas()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kelas::class, 'kelas', 'nama');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function guru()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Guru::class, 'wali_nip', 'nip');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tahunAjaran()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(TahunAjaran::class, 'tahun_ajaran', 'tahun');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Materi;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class MateriBaruNotification extends Notification
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected $materi;
|
||||||
|
|
||||||
|
public function __construct(Materi $materi)
|
||||||
|
{
|
||||||
|
$this->materi = $materi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return ['database'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDatabase($notifiable): array
|
||||||
|
{
|
||||||
|
$this->materi->loadMissing('mataPelajaran');
|
||||||
|
return [
|
||||||
|
'judul' => $this->materi->judul_materi,
|
||||||
|
'type' => "Materi",
|
||||||
|
'matapelajaran_id' => $this->materi->matapelajaran_id,
|
||||||
|
'matapelajaran_nama' => $this->materi->mataPelajaran->nama ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Quizzes;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class QuizBaruNotification extends Notification
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected $param;
|
||||||
|
|
||||||
|
public function __construct(Quizzes $quizzes)
|
||||||
|
{
|
||||||
|
$this->param = $quizzes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return ['database'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDatabase($notifiable): array
|
||||||
|
{
|
||||||
|
$this->param->loadMissing('mataPelajaran');
|
||||||
|
return [
|
||||||
|
'judul' => $this->param->judul,
|
||||||
|
'type' => "Quiz",
|
||||||
|
'matapelajaran_id' => $this->param->matapelajaran_id,
|
||||||
|
'matapelajaran_nama' => $this->param->mataPelajaran->nama ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class TugasBaruNotification extends Notification
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected $tugas;
|
||||||
|
|
||||||
|
public function __construct(Tugas $tugas)
|
||||||
|
{
|
||||||
|
$this->tugas = $tugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return ['database'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDatabase($notifiable): array
|
||||||
|
{
|
||||||
|
// Pastikan relasi sudah di-load
|
||||||
|
$this->tugas->loadMissing('mataPelajaran');
|
||||||
|
return [
|
||||||
|
'judul' => $this->tugas->nama,
|
||||||
|
'type' => "Tugas",
|
||||||
|
'matapelajaran_id' => $this->tugas->matapelajaran_id,
|
||||||
|
'matapelajaran_nama' => $this->tugas->mataPelajaran->nama ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class AppServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
|
||||||
|
class AdminRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Admin $guru)
|
||||||
|
{
|
||||||
|
$this->model = $guru;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with('user')->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%")
|
||||||
|
->orWhere("nip", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->orWhereHas("user", function ($query) use ($search) {
|
||||||
|
$query->where("email", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"user_id" => $data["user_id"],
|
||||||
|
"nip" => $data["nip"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"nip" => $data["nip"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\SubmitTugas;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class ApiSubmitTugasRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(SubmitTugas $submitTugas)
|
||||||
|
{
|
||||||
|
$this->model = $submitTugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($request)
|
||||||
|
{
|
||||||
|
$tanggal = now(); // Ubah agar menyimpan datetime lengkap
|
||||||
|
$request->validate([
|
||||||
|
'tugas_id' => 'required|exists:tugas,id',
|
||||||
|
'nisn' => 'required|string|max:12',
|
||||||
|
'text' => 'nullable|required_without:file|string',
|
||||||
|
'file' => 'nullable|required_without:text|file|mimes:pdf,jpg,png',
|
||||||
|
'nilai' => 'nullable|integer|min:0|max:100'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$filePath = null;
|
||||||
|
|
||||||
|
if ($request->hasFile('file')) {
|
||||||
|
$filename = Str::uuid() . '.' . $request->file->extension();
|
||||||
|
$filePath = $request->file->storeAs('tugas/submit_tugas', $filename, 'public');
|
||||||
|
}
|
||||||
|
|
||||||
|
$submit = SubmitTugas::create([
|
||||||
|
'tugas_id' => $request->tugas_id,
|
||||||
|
'nisn' => $request->nisn,
|
||||||
|
'tanggal' => $tanggal, // simpan datetime lengkap
|
||||||
|
'text' => $request->text,
|
||||||
|
'file' => $filePath,
|
||||||
|
'nilai' => $request->nilai
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $submit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail($request)
|
||||||
|
{
|
||||||
|
// Cek jika ada parameter submit_id, maka ambil berdasarkan id
|
||||||
|
if ($request->has('submit_id')) {
|
||||||
|
$query = $this->model->with('siswa')->find($request->submit_id);
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: cari berdasarkan nisn dan tugas_id
|
||||||
|
$query = $this->model->with('siswa')->where(function ($q) use ($request) {
|
||||||
|
$q->where('nisn', $request->nisn)
|
||||||
|
->where('tugas_id', $request->tugas_id);
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($request)
|
||||||
|
{
|
||||||
|
$tanggal = now(); // Ubah agar menyimpan datetime lengkap
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'id' => 'required|exists:submit_tugas,id',
|
||||||
|
'nisn' => 'required|string|max:12',
|
||||||
|
'text' => 'nullable|string',
|
||||||
|
'nilai' => 'nullable|integer|min:0|max:100'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$submit = $this->model->findOrFail($request->id);
|
||||||
|
|
||||||
|
$filePath = $submit->file;
|
||||||
|
|
||||||
|
if ($request->hasFile('file')) {
|
||||||
|
if ($filePath && Storage::disk('public')->exists($filePath)) {
|
||||||
|
Storage::disk('public')->delete($filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = Str::uuid() . '.' . $request->file->extension();
|
||||||
|
$filePath = $request->file->storeAs('tugas/submit_tugas', $filename, 'public');
|
||||||
|
}
|
||||||
|
|
||||||
|
$submit->update([
|
||||||
|
'nisn' => $request->nisn,
|
||||||
|
'tanggal' => $tanggal, // simpan datetime lengkap
|
||||||
|
'text' => $request->text,
|
||||||
|
'file' => $filePath,
|
||||||
|
'nilai' => $request->nilai
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $submit;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\SubmitTugas;
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use App\Http\Resources\TugasResource;
|
||||||
|
use GuzzleHttp\Psr7\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class ApiTugasRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Tugas $tugas)
|
||||||
|
{
|
||||||
|
$this->model = $tugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataApi($request, $param)
|
||||||
|
{
|
||||||
|
$query = $this->model->with(['mataPelajaran', 'submitTugas']);
|
||||||
|
|
||||||
|
if ($request->user->role == "siswa") {
|
||||||
|
if ($param->type_tugas == "selesai") {
|
||||||
|
$query->withWhereHas("submitTugas", function ($q) use ($request) {
|
||||||
|
$q->where('nisn', $request->nisn);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$query->whereDoesntHave("submitTugas", function ($q) use ($request) {
|
||||||
|
$q->where('nisn', $request->nisn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->where(function ($q) use ($request) {
|
||||||
|
$q->where("kelas", $request->kelas)
|
||||||
|
->where("tahun_ajaran", $request->tahun_ajaran);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$query->where(function ($q) use ($request, $param) {
|
||||||
|
$q->where("guru_nip", $request->nip)
|
||||||
|
->where('kelas', $param->kelas)
|
||||||
|
->where('tahun_ajaran', $param->tahun_ajaran);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->where('matapelajaran_id', $param->id_matpel);
|
||||||
|
|
||||||
|
$data = $query->get();
|
||||||
|
|
||||||
|
return TugasResource::collection($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubmitTugasSiswa($request)
|
||||||
|
{
|
||||||
|
$query = Siswa::where(function ($q) use ($request) {
|
||||||
|
$q->where("kelas", $request->kelas)
|
||||||
|
->where("tahun_ajaran", $request->tahun_ajaran);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($request->type_tugas == "selesai") {
|
||||||
|
$query->withWhereHas("submitTugas", function ($q) use ($request) {
|
||||||
|
$q->where("tugas_id", $request->tugas_id);
|
||||||
|
})->with([
|
||||||
|
'submitTugas' => function ($q) use ($request) {
|
||||||
|
$q->where("tugas_id", $request->tugas_id)
|
||||||
|
->with('tugas');
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$query->with('submitTugas')
|
||||||
|
->whereDoesntHave("submitTugas", function ($q) use ($request) {
|
||||||
|
$q->where("tugas_id", $request->tugas_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$data = $query->get();
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Models\WaliKelas;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
|
||||||
|
class DashboardRepository
|
||||||
|
{
|
||||||
|
public function getData($tahunAjaran = null, $kelas = null)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
// Get active academic year if not specified
|
||||||
|
if (!$tahunAjaran) {
|
||||||
|
$tahunAjaran = TahunAjaran::where('status', 'aktif')->first();
|
||||||
|
if ($tahunAjaran) {
|
||||||
|
$tahunAjaran = $tahunAjaran->tahun;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all academic years for dropdown
|
||||||
|
$data['tahun_ajaran_list'] = TahunAjaran::select('tahun')->get()->pluck('tahun');
|
||||||
|
// Get all classes for dropdown
|
||||||
|
$data['kelas_list'] = Kelas::select('nama')->get()->pluck('nama');
|
||||||
|
|
||||||
|
// User statistics (not affected by academic year or class)
|
||||||
|
$data['admin'] = User::where('role', "admin")->count();
|
||||||
|
$data['guru'] = User::where('role', "guru")->count();
|
||||||
|
|
||||||
|
// Academic statistics with year and class filter
|
||||||
|
$siswaQuery = Siswa::query();
|
||||||
|
$mataPelajaranQuery = MataPelajaran::query();
|
||||||
|
$waliKelasQuery = WaliKelas::query();
|
||||||
|
|
||||||
|
if ($tahunAjaran && $tahunAjaran !== 'all') {
|
||||||
|
$siswaQuery->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
$mataPelajaranQuery->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
$waliKelasQuery->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($kelas && $kelas !== 'all') {
|
||||||
|
$siswaQuery->where('kelas', $kelas);
|
||||||
|
$mataPelajaranQuery->where('kelas', $kelas);
|
||||||
|
$waliKelasQuery->where('kelas', $kelas);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['siswa'] = $siswaQuery->count();
|
||||||
|
// Kelas count needs special handling as it's not directly tied to siswa by year/class but to the existing classes
|
||||||
|
// If filtering by class, we only count that specific class, otherwise all classes
|
||||||
|
$data['kelas'] = ($kelas && $kelas !== 'all') ? 1 : Kelas::count();
|
||||||
|
$data['mata_pelajaran'] = $mataPelajaranQuery->count();
|
||||||
|
$data['wali_kelas'] = $waliKelasQuery->count();
|
||||||
|
|
||||||
|
// Get active academic year info
|
||||||
|
$activeYear = TahunAjaran::where('status', 'aktif')->first();
|
||||||
|
if ($activeYear) {
|
||||||
|
$data['tahun_ajaran_aktif'] = $activeYear->tahun;
|
||||||
|
} else {
|
||||||
|
$data['tahun_ajaran_aktif'] = 'Belum ada tahun ajaran aktif';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store selected year and class
|
||||||
|
$data['selected_year'] = $tahunAjaran;
|
||||||
|
$data['selected_kelas'] = $kelas;
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
use App\Models\Materi;
|
||||||
|
use App\Models\QuizAttempts;
|
||||||
|
use App\Models\QuizLevelSetting;
|
||||||
|
use App\Models\Quizzes;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\SubmitTugas;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class GuruDashboardRepository
|
||||||
|
{
|
||||||
|
public function getDashboardData($tahunAjaran = 'all', $kelas = 'all', $quizStatus = 'all')
|
||||||
|
{
|
||||||
|
$guru = Auth::user()->guru;
|
||||||
|
|
||||||
|
// Get all academic years for filter based on guru's subjects
|
||||||
|
$tahunAjaranList = MataPelajaran::where('guru_nip', $guru->nip)
|
||||||
|
->distinct('tahun_ajaran')
|
||||||
|
->pluck('tahun_ajaran')
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// Get all classes for filter based on guru's subjects
|
||||||
|
$kelasList = MataPelajaran::where('guru_nip', $guru->nip)
|
||||||
|
->distinct('kelas')
|
||||||
|
->pluck('kelas')
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// Get active academic year
|
||||||
|
$tahunAjaranAktif = TahunAjaran::where('status', 'aktif')->first();
|
||||||
|
|
||||||
|
// Get relevant MataPelajaran first based on guru_nip and tahun_ajaran
|
||||||
|
$guruMataPelajaranQuery = MataPelajaran::where('guru_nip', $guru->nip);
|
||||||
|
|
||||||
|
if ($tahunAjaran !== 'all') {
|
||||||
|
$guruMataPelajaranQuery->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
}
|
||||||
|
if ($kelas !== 'all') {
|
||||||
|
$guruMataPelajaranQuery->where('kelas', $kelas);
|
||||||
|
}
|
||||||
|
$guruMataPelajaranIds = $guruMataPelajaranQuery->pluck('id')->toArray();
|
||||||
|
$guruMataPelajaranClasses = $guruMataPelajaranQuery->pluck('kelas')->unique()->toArray();
|
||||||
|
|
||||||
|
// Now build the kelasQuery based on these class names
|
||||||
|
$kelasQuery = Kelas::whereIn('nama', $guruMataPelajaranClasses);
|
||||||
|
|
||||||
|
// Get subjects taught by this teacher (this query already correctly uses guru_nip)
|
||||||
|
$mataPelajaranQuery = MataPelajaran::where('guru_nip', $guru->nip);
|
||||||
|
|
||||||
|
// Apply filters if not 'all'
|
||||||
|
if ($tahunAjaran !== 'all') {
|
||||||
|
$mataPelajaranQuery->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($kelas !== 'all') {
|
||||||
|
$kelasQuery->where('nama', $kelas);
|
||||||
|
$mataPelajaranQuery->where('kelas', $kelas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get counts
|
||||||
|
$kelasCount = $kelasQuery->count();
|
||||||
|
$mataPelajaranCount = $mataPelajaranQuery->count();
|
||||||
|
|
||||||
|
// Get total students from these classes
|
||||||
|
$siswaCount = Siswa::whereIn('kelas', $kelasQuery->pluck('nama'))->count();
|
||||||
|
|
||||||
|
// New features: Total Tugas, Materi, Quiz
|
||||||
|
$totalTugas = Tugas::where('guru_nip', $guru->nip)
|
||||||
|
->when($tahunAjaran !== 'all', function ($query) use ($tahunAjaran) {
|
||||||
|
return $query->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
})
|
||||||
|
->when($kelas !== 'all', function ($query) use ($kelas) {
|
||||||
|
return $query->where('kelas', $kelas);
|
||||||
|
})
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$totalMateri = Materi::whereIn('matapelajaran_id', $guruMataPelajaranIds)
|
||||||
|
->when($tahunAjaran !== 'all', function ($query) use ($tahunAjaran) {
|
||||||
|
return $query->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
})
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$totalQuiz = Quizzes::whereIn('matapelajaran_id', $guruMataPelajaranIds)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
// Quiz Results (Passed/Failed)
|
||||||
|
$passedQuizzes = 0;
|
||||||
|
$failedQuizzes = 0;
|
||||||
|
|
||||||
|
$quizAttempts = QuizAttempts::whereHas('quizzes.mataPelajaran', function ($query) use ($guru, $tahunAjaran, $kelas) {
|
||||||
|
$query->where('guru_nip', $guru->nip);
|
||||||
|
if ($tahunAjaran !== 'all') {
|
||||||
|
$query->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
}
|
||||||
|
if ($kelas !== 'all') {
|
||||||
|
$query->where('kelas', $kelas);
|
||||||
|
}
|
||||||
|
})->get();
|
||||||
|
|
||||||
|
foreach ($quizAttempts as $attempt) {
|
||||||
|
$quizLevelSettings = QuizLevelSetting::where('quiz_id', $attempt->quiz_id)->first();
|
||||||
|
if ($quizLevelSettings) {
|
||||||
|
$jumlahSoalPerLevel = json_decode($quizLevelSettings->jumlah_soal_per_level, true);
|
||||||
|
$totalSkorLevel = 0;
|
||||||
|
foreach (json_decode($quizLevelSettings->skor_level) as $key => $value) {
|
||||||
|
$totalSkorLevel += $value * (int) $jumlahSoalPerLevel[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
$persentase = ($totalSkorLevel > 0) ? round(($attempt->skor / $totalSkorLevel) * 100) : 0;
|
||||||
|
$kkm = $quizLevelSettings->kkm;
|
||||||
|
|
||||||
|
if ($persentase >= $kkm) {
|
||||||
|
$passedQuizzes++;
|
||||||
|
} else {
|
||||||
|
$failedQuizzes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare data for Mata Pelajaran Distribution Chart
|
||||||
|
$mataPelajaranChartLabels = [];
|
||||||
|
$mataPelajaranChartData = [];
|
||||||
|
$mataPelajaranWithClasses = MataPelajaran::where('guru_nip', $guru->nip)
|
||||||
|
->when($tahunAjaran !== 'all', function ($query) use ($tahunAjaran) {
|
||||||
|
return $query->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
})
|
||||||
|
->when($kelas !== 'all', function ($query) use ($kelas) {
|
||||||
|
return $query->where('kelas', $kelas);
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($mataPelajaranWithClasses as $mp) {
|
||||||
|
$studentsInClass = Siswa::where('kelas', $mp->kelas)->count();
|
||||||
|
$mataPelajaranChartLabels[] = $mp->nama; // Assuming 'nama' is the subject name
|
||||||
|
$mataPelajaranChartData[] = $studentsInClass; // Count students in the associated class
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare data for Siswa per Kelas Chart
|
||||||
|
$kelasChartLabels = [];
|
||||||
|
$kelasChartData = [];
|
||||||
|
$guruClasses = Kelas::whereIn('nama', $guruMataPelajaranClasses)
|
||||||
|
->when($kelas !== 'all', function ($query) use ($kelas) {
|
||||||
|
return $query->where('nama', $kelas);
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($guruClasses as $k) {
|
||||||
|
$siswaInKelasCount = Siswa::where('kelas', $k->nama)->count();
|
||||||
|
$kelasChartLabels[] = $k->nama;
|
||||||
|
$kelasChartData[] = $siswaInKelasCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare data for Nilai Rata-rata Tugas per Mata Pelajaran dan Kelas Chart
|
||||||
|
$tugasChartLabels = [];
|
||||||
|
$tugasChartData = [];
|
||||||
|
$tugasChartDataPerTugas = [];
|
||||||
|
|
||||||
|
// Get all mata pelajaran that the teacher teaches with filters
|
||||||
|
$mataPelajaranQuery = MataPelajaran::where('guru_nip', $guru->nip)
|
||||||
|
->when($tahunAjaran !== 'all', function ($query) use ($tahunAjaran) {
|
||||||
|
return $query->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
})
|
||||||
|
->when($kelas !== 'all', function ($query) use ($kelas) {
|
||||||
|
return $query->where('kelas', $kelas);
|
||||||
|
})
|
||||||
|
->orderBy('nama', 'asc');
|
||||||
|
|
||||||
|
$mataPelajaranList = $mataPelajaranQuery->get();
|
||||||
|
|
||||||
|
foreach ($mataPelajaranList as $matpel) {
|
||||||
|
// Get all tasks for this mata pelajaran and class
|
||||||
|
$tugasForMatpel = Tugas::where('guru_nip', $guru->nip)
|
||||||
|
->where('matapelajaran_id', $matpel->id)
|
||||||
|
->where('kelas', $matpel->kelas)
|
||||||
|
->when($tahunAjaran !== 'all', function ($query) use ($tahunAjaran) {
|
||||||
|
return $query->where('tahun_ajaran', $tahunAjaran);
|
||||||
|
})
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($tugasForMatpel as $tugas) {
|
||||||
|
// Get average score for this task
|
||||||
|
$avgNilai = SubmitTugas::where('tugas_id', $tugas->id)
|
||||||
|
->whereNotNull('nilai')
|
||||||
|
->avg('nilai');
|
||||||
|
|
||||||
|
if ($avgNilai !== null) {
|
||||||
|
$tugasChartLabels[] = "{$matpel->nama} ({$matpel->kelas}) - {$tugas->nama}";
|
||||||
|
$tugasChartData[] = round($avgNilai, 1);
|
||||||
|
|
||||||
|
$tugasChartDataPerTugas[] = [
|
||||||
|
'id_tugas' => $tugas->id,
|
||||||
|
'nama_tugas' => $tugas->nama,
|
||||||
|
'mata_pelajaran' => $matpel->nama,
|
||||||
|
'kelas' => $matpel->kelas,
|
||||||
|
'rata_rata' => round($avgNilai, 1),
|
||||||
|
'jumlah_submit' => SubmitTugas::where('tugas_id', $tugas->id)->count(),
|
||||||
|
'jumlah_dinilai' => SubmitTugas::where('tugas_id', $tugas->id)->whereNotNull('nilai')->count(),
|
||||||
|
'tanggal_tugas' => $tugas->tanggal,
|
||||||
|
'tenggat_waktu' => $tugas->tenggat
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'selected_year' => $tahunAjaran,
|
||||||
|
'selected_kelas' => $kelas,
|
||||||
|
'selected_quiz_status' => $quizStatus,
|
||||||
|
'tahun_ajaran_list' => $tahunAjaranList,
|
||||||
|
'kelas_list' => $kelasList,
|
||||||
|
'tahun_ajaran_aktif' => $tahunAjaranAktif ? $tahunAjaranAktif->tahun : '-',
|
||||||
|
'kelas' => $kelasCount,
|
||||||
|
'mata_pelajaran' => $mataPelajaranCount,
|
||||||
|
'siswa' => $siswaCount,
|
||||||
|
'total_tugas' => $totalTugas,
|
||||||
|
'total_materi' => $totalMateri,
|
||||||
|
'total_quiz' => $totalQuiz,
|
||||||
|
'passed_quizzes' => $passedQuizzes,
|
||||||
|
'failed_quizzes' => $failedQuizzes,
|
||||||
|
'mata_pelajaran_chart' => [
|
||||||
|
'labels' => $mataPelajaranChartLabels,
|
||||||
|
'data' => $mataPelajaranChartData,
|
||||||
|
],
|
||||||
|
'kelas_chart' => [
|
||||||
|
'labels' => $kelasChartLabels,
|
||||||
|
'data' => $kelasChartData,
|
||||||
|
],
|
||||||
|
'tugas_chart' => [
|
||||||
|
'labels' => $tugasChartLabels,
|
||||||
|
'data' => $tugasChartData,
|
||||||
|
'data_per_tugas' => $tugasChartDataPerTugas,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Guru;
|
||||||
|
|
||||||
|
class GuruRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Guru $guru)
|
||||||
|
{
|
||||||
|
$this->model = $guru;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with('user')->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->orWhereHas("user", function ($query) use ($search) {
|
||||||
|
$query->where("email", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"user_id" => $data["user_id"],
|
||||||
|
"nip" => $data["nip"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"nip" => $data["nip"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Kelas;
|
||||||
|
|
||||||
|
class KelasRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Kelas $kelas)
|
||||||
|
{
|
||||||
|
$this->model = $kelas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
// return $this->model->where('id', $id)->update([
|
||||||
|
// "nama" => $data["nama"],
|
||||||
|
// ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($kelas)
|
||||||
|
{
|
||||||
|
return $this->model->where('nama', $kelas)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\MataPelajaran;
|
||||||
|
|
||||||
|
class MataPelajaranRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(MataPelajaran $mataPelajaran)
|
||||||
|
{
|
||||||
|
$this->model = $mataPelajaran;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with(["guru", "kelas", "tahunAjaran"])->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%")
|
||||||
|
->orWhere("kelas", "like", "%" . $search . "%")
|
||||||
|
->orWhere("tahun_ajaran", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->orWhereHas("guru", function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"guru_nip" => $data["guru_nip"],
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"guru_nip" => $data["guru_nip"],
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
// return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Materi;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Notifications\MateriBaruNotification;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class MateriRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Materi $materi)
|
||||||
|
{
|
||||||
|
$this->model = $materi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with('mataPelajaran')->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataApi($matapelajaranId, $semester = 1, $type = "buku", $request)
|
||||||
|
{
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($matapelajaranId, $semester, $type) {
|
||||||
|
$query->where("matapelajaran_id", $matapelajaranId)
|
||||||
|
->where("semester", $semester)
|
||||||
|
->where("type", $type);
|
||||||
|
})
|
||||||
|
->with("mataPelajaran");
|
||||||
|
|
||||||
|
if ($request->user->role == "siswa") {
|
||||||
|
$query->where(function ($query) use ($request) {
|
||||||
|
$query->where("tahun_ajaran", $request->tahun_ajaran);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$query->whereHas("mataPelajaran", function ($query) use ($request) {
|
||||||
|
$query->where("guru_nip", $request->nip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $query->get();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$guru = Auth::user()->guru;
|
||||||
|
$query = $this->model->with('mataPelajaran')
|
||||||
|
->whereHas('mataPelajaran', function ($query) use ($guru) {
|
||||||
|
$query->where('guru_nip', $guru->nip);
|
||||||
|
})
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("semester", "like", "%" . $search . "%")
|
||||||
|
->orWhere("type", "like", "%" . $search . "%")
|
||||||
|
->orWhere("judul_materi", "like", "%" . $search . "%")
|
||||||
|
->orWhere("tahun_ajaran", "like", "%" . $search . "%")
|
||||||
|
->orWhereHas("mataPelajaran", function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
$materi = $this->model->create([
|
||||||
|
"tanggal" => $data["tanggal"],
|
||||||
|
"matapelajaran_id" => $data["matapelajaran_id"],
|
||||||
|
"semester" => $data["semester"],
|
||||||
|
"type" => $data["type"],
|
||||||
|
"judul_materi" => $data["judul_materi"],
|
||||||
|
"deskripsi" => $data["deskripsi"],
|
||||||
|
"path" => $data["path"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cari siswa berdasarkan kelas dan tahun ajaran
|
||||||
|
$siswas = Siswa::where('tahun_ajaran', $data['tahun_ajaran'])->get();
|
||||||
|
|
||||||
|
// Kirim notifikasi ke setiap siswa
|
||||||
|
$materi->load('mataPelajaran');
|
||||||
|
foreach ($siswas as $siswa) {
|
||||||
|
$siswa->notify(new MateriBaruNotification($materi));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $materi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"tanggal" => $data["tanggal"],
|
||||||
|
"matapelajaran_id" => $data["matapelajaran_id"],
|
||||||
|
"semester" => $data["semester"],
|
||||||
|
"type" => $data["type"],
|
||||||
|
"judul_materi" => $data["judul_materi"],
|
||||||
|
"deskripsi" => $data["deskripsi"],
|
||||||
|
"path" => $data["path"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Traits\ApiResponse;
|
||||||
|
use App\Models\QuizAttemptAnswers;
|
||||||
|
use App\Models\QuizAttempts;
|
||||||
|
use App\Models\QuizLevelSetting;
|
||||||
|
use App\Models\QuizQuestions;
|
||||||
|
use App\Models\Quizzes;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class QuizRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
protected $modelQuizzes;
|
||||||
|
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function __construct(QuizQuestions $quizQuestions, Quizzes $quizzes)
|
||||||
|
{
|
||||||
|
$this->model = $quizQuestions;
|
||||||
|
$this->modelQuizzes = $quizzes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiGetQuizzes($id)
|
||||||
|
{
|
||||||
|
$nisn = Auth::user()->siswa->nisn;
|
||||||
|
$query = Quizzes::where('matapelajaran_id', $id)
|
||||||
|
->with([
|
||||||
|
'quizAttempt' => function ($q) use ($nisn) {
|
||||||
|
$q->where('nisn', $nisn);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiGetQuizzesGuru($request, $id)
|
||||||
|
{
|
||||||
|
$query = Quizzes::where('matapelajaran_id', $id)
|
||||||
|
->whereHas('mataPelajaran', function ($q) use ($request) {
|
||||||
|
$q->where('kelas', $request->kelas)
|
||||||
|
->where('tahun_ajaran', $request->tahun_ajaran);
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($request)
|
||||||
|
{
|
||||||
|
$query = $this->model->with('quiz')
|
||||||
|
->whereHas('quiz', function ($q) use ($request) {
|
||||||
|
$q->where('matapelajaran_id', $request->matapelajaran_id)
|
||||||
|
->where('judul', $request->judul);
|
||||||
|
})
|
||||||
|
->whereHas('quiz.mataPelajaran', function ($q) use ($request) {
|
||||||
|
$q->where('kelas', $request->kelas)
|
||||||
|
->where('tahun_ajaran', $request->tahun_ajaran);
|
||||||
|
})->get();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nextQuestion($attempt_id)
|
||||||
|
{
|
||||||
|
$attempt = QuizAttempts::findOrFail((int) $attempt_id);
|
||||||
|
|
||||||
|
// Ambil total soal tampil dari quiz
|
||||||
|
$quiz = Quizzes::findOrFail((int) $attempt->quiz_id);
|
||||||
|
|
||||||
|
// Kalau sudah mencapai total soal tampil, jangan kasih soal lagi
|
||||||
|
if ($attempt->jumlahJawaban() >= $quiz->total_soal_tampil) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Semua soal sudah dijawab.',
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kalau belum, ambil 1 soal random di level sekarang
|
||||||
|
// Find the attempt by given ID
|
||||||
|
$question = QuizQuestions::where('quiz_id', $attempt->quiz_id)
|
||||||
|
->where('level', $attempt->level_akhir)
|
||||||
|
// Get the total soal tampil from the quiz
|
||||||
|
->whereDoesntHave('attemptAnswers', function ($q) use ($attempt_id) {
|
||||||
|
$q->where('attempt_id', $attempt_id);
|
||||||
|
})
|
||||||
|
->inRandomOrder()
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$quizAttemptAnswer = QuizAttemptAnswers::where('attempt_id', $attempt_id)->count();
|
||||||
|
|
||||||
|
if (!$question) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Tidak ada soal lagi di level ini.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$question['pertanyaan'] = $quizAttemptAnswer + 1 . ". " . $question->pertanyaan;
|
||||||
|
|
||||||
|
return $question;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function answer($request, $attempt_id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'question_id' => 'required|integer',
|
||||||
|
// Hilangkan validasi in:a,b,c,d agar jawaban_siswa boleh kosong
|
||||||
|
'jawaban_siswa' => 'nullable',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Validasi attempt
|
||||||
|
$attempt = QuizAttempts::findOrFail($attempt_id);
|
||||||
|
|
||||||
|
// Validasi question exists dan belongs to the correct quiz
|
||||||
|
$question = QuizQuestions::where('id', $request->question_id)
|
||||||
|
->where('quiz_id', $attempt->quiz_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$question) {
|
||||||
|
throw new \Exception('The selected question is invalid or does not belong to this quiz.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$quizzes = Quizzes::findOrFail($attempt->quiz_id);
|
||||||
|
$quizLevelSettings = QuizLevelSetting::where('quiz_id', $attempt->quiz_id)->first();
|
||||||
|
|
||||||
|
$jumlahSoalPerLevel = json_decode($quizLevelSettings->jumlah_soal_per_level, true);
|
||||||
|
$batasNaikLevel = json_decode($quizLevelSettings->batas_naik_level, true);
|
||||||
|
|
||||||
|
// Jika jawaban kosong, otomatis salah
|
||||||
|
$isCorrect = ($request->jawaban_siswa && $request->jawaban_siswa == $question->jawaban_benar) ? 1 : 0;
|
||||||
|
|
||||||
|
// Hitung skor tambahan
|
||||||
|
$skor_tambahan = 0;
|
||||||
|
if ($isCorrect) {
|
||||||
|
$skor_tambahan = $question->skor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tambahkan skor ke attempt
|
||||||
|
$attempt->skor += $skor_tambahan;
|
||||||
|
|
||||||
|
// Simpan jawaban (jika kosong, simpan string kosong)
|
||||||
|
QuizAttemptAnswers::create([
|
||||||
|
'attempt_id' => $attempt->id,
|
||||||
|
'question_id' => $question->id,
|
||||||
|
'jawaban_siswa' => $request->jawaban_siswa ?? '',
|
||||||
|
'benar' => $isCorrect,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update jumlah soal dijawab
|
||||||
|
$attempt->jumlah_soal_dijawab++;
|
||||||
|
|
||||||
|
// cek fase
|
||||||
|
foreach ($jumlahSoalPerLevel as $key => $value) {
|
||||||
|
$lvlNumber = preg_replace('/[^0-9]/', '', $key);
|
||||||
|
|
||||||
|
|
||||||
|
if ($attempt->fase == $lvlNumber) {
|
||||||
|
$benar = json_decode($attempt->benar, true) ?? [];
|
||||||
|
$jumlahFase = count($jumlahSoalPerLevel);
|
||||||
|
$isLastFase = $attempt->fase == $jumlahFase;
|
||||||
|
|
||||||
|
if (!$isLastFase && $isCorrect) {
|
||||||
|
$benar['fase' . $lvlNumber] = ($benar['fase' . $lvlNumber] ?? 0) + ($isCorrect ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$attempt->benar = json_encode($benar);
|
||||||
|
|
||||||
|
if ($attempt->jumlah_soal_dijawab == $value) {
|
||||||
|
if ($benar['fase' . $lvlNumber] >= $batasNaikLevel['fase' . $lvlNumber]) {
|
||||||
|
// if ($attempt->level_akhir < $lvlNumber) {
|
||||||
|
$attempt->level_akhir += 1;
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
$attempt->level_akhir;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attempt->fase += 1;
|
||||||
|
$attempt->jumlah_soal_dijawab = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$attempt->save();
|
||||||
|
|
||||||
|
$jumlah_jawaban = QuizAttemptAnswers::where('attempt_id', $attempt->id)->count();
|
||||||
|
$total_soal_tampil = $quizzes->total_soal_tampil;
|
||||||
|
$selesai = $jumlah_jawaban >= $total_soal_tampil;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'quiz_id' => $attempt->quiz_id,
|
||||||
|
'correct' => $isCorrect,
|
||||||
|
'fase' => $attempt->fase,
|
||||||
|
'new_level' => $attempt->level_akhir,
|
||||||
|
'skor_sementara' => $attempt->skor,
|
||||||
|
'selesai' => $selesai,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFinishQuiz($quizId)
|
||||||
|
{
|
||||||
|
$attempt = QuizAttempts::where('quiz_id', $quizId)
|
||||||
|
->where('nisn', Auth::user()->siswa->nisn)
|
||||||
|
->orderByDesc('id') // ambil attempt terbaru
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$attempt) {
|
||||||
|
return $this->errorApiResponse('Data tidak ditemukan', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$attempt->jumlah_soal = $attempt->quizzes()->first()->total_soal_tampil;
|
||||||
|
$attempt->jawaban_benar = (string) QuizAttemptAnswers::where('attempt_id', $attempt->id)->where('benar', 1)->count();
|
||||||
|
$attempt->jawaban_salah = (string) QuizAttemptAnswers::where('attempt_id', $attempt->id)->where('benar', "0")->count();
|
||||||
|
|
||||||
|
return $this->okApiResponse($attempt);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Siswa;
|
||||||
|
|
||||||
|
class SiswaRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Siswa $siswa)
|
||||||
|
{
|
||||||
|
$this->model = $siswa;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with('user')->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%")
|
||||||
|
->orWhere("nisn", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->orWhereHas("user", function ($query) use ($search) {
|
||||||
|
$query->where("email", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"user_id" => $data["user_id"],
|
||||||
|
"nisn" => $data["nisn"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"nisn" => $data["nisn"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Guru;
|
||||||
|
|
||||||
|
class SubmitTugasRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(Guru $guru)
|
||||||
|
{
|
||||||
|
$this->model = $guru;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with('user')->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->orWhereHas("user", function ($query) use ($search) {
|
||||||
|
$query->where("email", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"user_id" => $data["user_id"],
|
||||||
|
"nip" => $data["nip"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"nip" => $data["nip"],
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"jk" => $data["jk"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
|
||||||
|
class TahunAjaranRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(TahunAjaran $tahunAjaran)
|
||||||
|
{
|
||||||
|
$this->model = $tahunAjaran;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("tahun", "like", "%" . $search . "%")
|
||||||
|
->orWhere("status", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"tahun" => $data["tahun"],
|
||||||
|
"status" => "aktif",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $tahun)
|
||||||
|
{
|
||||||
|
return $this->model->where('tahun', $tahun)->update([
|
||||||
|
"status" => $data["status"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($tahun)
|
||||||
|
{
|
||||||
|
return $this->model->where('tahun', $tahun)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\Tugas;
|
||||||
|
use App\Notifications\TugasBaruNotification;
|
||||||
|
use GuzzleHttp\Psr7\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class TugasRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
protected $nipUser;
|
||||||
|
|
||||||
|
public function __construct(Tugas $tugas)
|
||||||
|
{
|
||||||
|
$this->model = $tugas;
|
||||||
|
$this->nipUser = Auth::user()->guru->nip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataApi($request)
|
||||||
|
{
|
||||||
|
$query = $this->model->with('mataPelajaran');
|
||||||
|
|
||||||
|
if ($request->user->role == "siswa") {
|
||||||
|
$query->where(function ($query) use ($request) {
|
||||||
|
$query->where("kelas", $request->kelas)
|
||||||
|
->where("tahun_ajaran", $request->tahun_ajaran);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$query->where(function ($query) use ($request) {
|
||||||
|
$query->where("guru_nip", $request->nip)
|
||||||
|
->orWhere('kelas', $request->kelas)
|
||||||
|
->orWhere('kelas', $request->tahun_ajaran);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$query = $query->get();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with('mataPelajaran')->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$nipGuru = Auth::user()->guru->nip;
|
||||||
|
$query = $this->model->where('guru_nip', $nipGuru)
|
||||||
|
->where(function ($query) use ($search, $nipGuru) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%")
|
||||||
|
->orWhere("kelas", "like", "%" . $search . "%")
|
||||||
|
->orWhere("tahun_ajaran", "like", "%" . $search . "%")
|
||||||
|
->orWhereHas("mataPelajaran", function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
$tugas = $this->model->create([
|
||||||
|
"tanggal" => $data["tanggal"],
|
||||||
|
"tenggat" => $data["tenggat"],
|
||||||
|
"guru_nip" => $this->nipUser,
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"matapelajaran_id" => $data["matapelajaran_id"],
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
"deskripsi" => $data["deskripsi"] ?? null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cari siswa berdasarkan kelas dan tahun ajaran
|
||||||
|
$siswas = Siswa::where('kelas', $data['kelas'])
|
||||||
|
->where('tahun_ajaran', $data['tahun_ajaran'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Kirim notifikasi ke setiap siswa
|
||||||
|
foreach ($siswas as $siswa) {
|
||||||
|
$siswa->notify(new TugasBaruNotification($tugas));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tugas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"tanggal" => $data["tanggal"],
|
||||||
|
"tenggat" => $data["tenggat"],
|
||||||
|
"guru_nip" => $this->nipUser,
|
||||||
|
"nama" => $data["nama"],
|
||||||
|
"matapelajaran_id" => $data["matapelajaran_id"],
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
"deskripsi" => $data["deskripsi"] ?? null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class UserRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(User $user)
|
||||||
|
{
|
||||||
|
$this->model = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"email" => $data["email"],
|
||||||
|
"password" => $data["pass"],
|
||||||
|
"role" => $data["role"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"email" => $data["email"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\WaliKelas;
|
||||||
|
|
||||||
|
class WaliKelasRepository
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(WaliKelas $waliKelas)
|
||||||
|
{
|
||||||
|
$this->model = $waliKelas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->model->with(["guru", "kelas"])->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($search, $limit = 10)
|
||||||
|
{
|
||||||
|
$search = strtolower($search);
|
||||||
|
$query = $this->model
|
||||||
|
->where(function ($query) use ($search) {
|
||||||
|
$query->where("tahun_ajaran", "like", "%" . $search . "%")
|
||||||
|
->orWhere("kelas", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->orWhereHas("guru", function ($query) use ($search) {
|
||||||
|
$query->where("nama", "like", "%" . $search . "%");
|
||||||
|
})
|
||||||
|
->paginate($limit);
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
return $this->model->create([
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
"wali_nip" => $data["wali_nip"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($data, $id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->update([
|
||||||
|
"kelas" => $data["kelas"],
|
||||||
|
"tahun_ajaran" => $data["tahun_ajaran"],
|
||||||
|
"wali_nip" => $data["wali_nip"],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
return $this->model->where('id', $id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class Icon extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new component instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the view / contents that represent the component.
|
||||||
|
*/
|
||||||
|
public function render(): View|Closure|string
|
||||||
|
{
|
||||||
|
return view('components.icon');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
|
|
||||||
|
define('LARAVEL_START', microtime(true));
|
||||||
|
|
||||||
|
// Register the Composer autoloader...
|
||||||
|
require __DIR__.'/vendor/autoload.php';
|
||||||
|
|
||||||
|
// Bootstrap Laravel and handle the command...
|
||||||
|
$status = (require_once __DIR__.'/bootstrap/app.php')
|
||||||
|
->handleCommand(new ArgvInput);
|
||||||
|
|
||||||
|
exit($status);
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Application;
|
||||||
|
use Illuminate\Foundation\Configuration\Exceptions;
|
||||||
|
use Illuminate\Foundation\Configuration\Middleware;
|
||||||
|
|
||||||
|
return Application::configure(basePath: dirname(__DIR__))
|
||||||
|
->withRouting(
|
||||||
|
web: __DIR__ . '/../routes/web.php',
|
||||||
|
api: __DIR__ . '/../routes/api.php',
|
||||||
|
commands: __DIR__ . '/../routes/console.php',
|
||||||
|
health: '/up',
|
||||||
|
)
|
||||||
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
|
$middleware->alias([
|
||||||
|
'role' => \App\Http\Middleware\RoleMiddleware::class,
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
->withExceptions(function (Exceptions $exceptions) {
|
||||||
|
//
|
||||||
|
})->create();
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
App\Providers\AppServiceProvider::class,
|
||||||
|
];
|
|
@ -0,0 +1,77 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://getcomposer.org/schema.json",
|
||||||
|
"name": "laravel/laravel",
|
||||||
|
"type": "project",
|
||||||
|
"description": "The skeleton application for the Laravel framework.",
|
||||||
|
"keywords": [
|
||||||
|
"laravel",
|
||||||
|
"framework"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"require": {
|
||||||
|
"php": "^8.2",
|
||||||
|
"laravel/framework": "^11.31",
|
||||||
|
"laravel/sanctum": "^4.0",
|
||||||
|
"laravel/tinker": "^2.9",
|
||||||
|
"maatwebsite/excel": "^3.1",
|
||||||
|
"realrashid/sweet-alert": "^7.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"fakerphp/faker": "^1.23",
|
||||||
|
"laravel/pail": "^1.1",
|
||||||
|
"laravel/pint": "^1.13",
|
||||||
|
"laravel/sail": "^1.26",
|
||||||
|
"mockery/mockery": "^1.6",
|
||||||
|
"nunomaduro/collision": "^8.1",
|
||||||
|
"phpunit/phpunit": "^11.0.1"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\": "app/",
|
||||||
|
"Database\\Factories\\": "database/factories/",
|
||||||
|
"Database\\Seeders\\": "database/seeders/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"post-autoload-dump": [
|
||||||
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
|
"@php artisan package:discover --ansi"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||||
|
],
|
||||||
|
"post-root-package-install": [
|
||||||
|
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||||
|
],
|
||||||
|
"post-create-project-cmd": [
|
||||||
|
"@php artisan key:generate --ansi",
|
||||||
|
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||||
|
"@php artisan migrate --graceful --ansi"
|
||||||
|
],
|
||||||
|
"dev": [
|
||||||
|
"Composer\\Config::disableProcessTimeout",
|
||||||
|
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"dont-discover": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"preferred-install": "dist",
|
||||||
|
"sort-packages": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"pestphp/pest-plugin": true,
|
||||||
|
"php-http/discovery": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"prefer-stable": true
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value is the name of your application, which will be used when the
|
||||||
|
| framework needs to place the application's name in a notification or
|
||||||
|
| other UI elements where an application name needs to be displayed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'name' => env('APP_NAME', 'Laravel'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Environment
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the "environment" your application is currently
|
||||||
|
| running in. This may determine how you prefer to configure various
|
||||||
|
| services the application utilizes. Set this in your ".env" file.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'env' => env('APP_ENV', 'production'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Debug Mode
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When your application is in debug mode, detailed error messages with
|
||||||
|
| stack traces will be shown on every error that occurs within your
|
||||||
|
| application. If disabled, a simple generic error page is shown.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'debug' => (bool) env('APP_DEBUG', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application URL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This URL is used by the console to properly generate URLs when using
|
||||||
|
| the Artisan command line tool. You should set this to the root of
|
||||||
|
| the application so that it's available within Artisan commands.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'url' => env('APP_URL', 'http://localhost'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Timezone
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the default timezone for your application, which
|
||||||
|
| will be used by the PHP date and date-time functions. The timezone
|
||||||
|
| is set to "UTC" by default as it is suitable for most use cases.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Locale Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The application locale determines the default locale that will be used
|
||||||
|
| by Laravel's translation / localization methods. This option can be
|
||||||
|
| set to any locale for which you plan to have translation strings.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'locale' => env('APP_LOCALE', 'en'),
|
||||||
|
|
||||||
|
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
|
||||||
|
|
||||||
|
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Encryption Key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This key is utilized by Laravel's encryption services and should be set
|
||||||
|
| to a random, 32 character string to ensure that all encrypted values
|
||||||
|
| are secure. You should do this prior to deploying the application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cipher' => 'AES-256-CBC',
|
||||||
|
|
||||||
|
'key' => env('APP_KEY'),
|
||||||
|
|
||||||
|
'previous_keys' => [
|
||||||
|
...array_filter(
|
||||||
|
explode(',', env('APP_PREVIOUS_KEYS', ''))
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Maintenance Mode Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These configuration options determine the driver used to determine and
|
||||||
|
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||||
|
| allow maintenance mode to be controlled across multiple machines.
|
||||||
|
|
|
||||||
|
| Supported drivers: "file", "cache"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'maintenance' => [
|
||||||
|
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||||
|
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Defaults
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option defines the default authentication "guard" and password
|
||||||
|
| reset "broker" for your application. You may change these values
|
||||||
|
| as required, but they're a perfect start for most applications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'defaults' => [
|
||||||
|
'guard' => env('AUTH_GUARD', 'web'),
|
||||||
|
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Guards
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Next, you may define every authentication guard for your application.
|
||||||
|
| Of course, a great default configuration has been defined for you
|
||||||
|
| which utilizes session storage plus the Eloquent user provider.
|
||||||
|
|
|
||||||
|
| All authentication guards have a user provider, which defines how the
|
||||||
|
| users are actually retrieved out of your database or other storage
|
||||||
|
| system used by the application. Typically, Eloquent is utilized.
|
||||||
|
|
|
||||||
|
| Supported: "session"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'guards' => [
|
||||||
|
'web' => [
|
||||||
|
'driver' => 'session',
|
||||||
|
'provider' => 'users',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| User Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| All authentication guards have a user provider, which defines how the
|
||||||
|
| users are actually retrieved out of your database or other storage
|
||||||
|
| system used by the application. Typically, Eloquent is utilized.
|
||||||
|
|
|
||||||
|
| If you have multiple user tables or models you may configure multiple
|
||||||
|
| providers to represent the model / table. These providers may then
|
||||||
|
| be assigned to any extra authentication guards you have defined.
|
||||||
|
|
|
||||||
|
| Supported: "database", "eloquent"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'providers' => [
|
||||||
|
'users' => [
|
||||||
|
'driver' => 'eloquent',
|
||||||
|
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||||
|
],
|
||||||
|
|
||||||
|
// 'users' => [
|
||||||
|
// 'driver' => 'database',
|
||||||
|
// 'table' => 'users',
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Resetting Passwords
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These configuration options specify the behavior of Laravel's password
|
||||||
|
| reset functionality, including the table utilized for token storage
|
||||||
|
| and the user provider that is invoked to actually retrieve users.
|
||||||
|
|
|
||||||
|
| The expiry time is the number of minutes that each reset token will be
|
||||||
|
| considered valid. This security feature keeps tokens short-lived so
|
||||||
|
| they have less time to be guessed. You may change this as needed.
|
||||||
|
|
|
||||||
|
| The throttle setting is the number of seconds a user must wait before
|
||||||
|
| generating more password reset tokens. This prevents the user from
|
||||||
|
| quickly generating a very large amount of password reset tokens.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'passwords' => [
|
||||||
|
'users' => [
|
||||||
|
'provider' => 'users',
|
||||||
|
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
|
||||||
|
'expire' => 60,
|
||||||
|
'throttle' => 60,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Confirmation Timeout
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define the amount of seconds before a password confirmation
|
||||||
|
| window expires and users are asked to re-enter their password via the
|
||||||
|
| confirmation screen. By default, the timeout lasts for three hours.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Cache Store
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default cache store that will be used by the
|
||||||
|
| framework. This connection is utilized if another isn't explicitly
|
||||||
|
| specified when running a cache operation inside the application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('CACHE_STORE', 'database'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Stores
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define all of the cache "stores" for your application as
|
||||||
|
| well as their drivers. You may even define multiple stores for the
|
||||||
|
| same cache driver to group types of items stored in your caches.
|
||||||
|
|
|
||||||
|
| Supported drivers: "array", "database", "file", "memcached",
|
||||||
|
| "redis", "dynamodb", "octane", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'stores' => [
|
||||||
|
|
||||||
|
'array' => [
|
||||||
|
'driver' => 'array',
|
||||||
|
'serialize' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'database' => [
|
||||||
|
'driver' => 'database',
|
||||||
|
'connection' => env('DB_CACHE_CONNECTION'),
|
||||||
|
'table' => env('DB_CACHE_TABLE', 'cache'),
|
||||||
|
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
|
||||||
|
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'file' => [
|
||||||
|
'driver' => 'file',
|
||||||
|
'path' => storage_path('framework/cache/data'),
|
||||||
|
'lock_path' => storage_path('framework/cache/data'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'memcached' => [
|
||||||
|
'driver' => 'memcached',
|
||||||
|
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
|
||||||
|
'sasl' => [
|
||||||
|
env('MEMCACHED_USERNAME'),
|
||||||
|
env('MEMCACHED_PASSWORD'),
|
||||||
|
],
|
||||||
|
'options' => [
|
||||||
|
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||||
|
],
|
||||||
|
'servers' => [
|
||||||
|
[
|
||||||
|
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('MEMCACHED_PORT', 11211),
|
||||||
|
'weight' => 100,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
'driver' => 'redis',
|
||||||
|
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
|
||||||
|
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'dynamodb' => [
|
||||||
|
'driver' => 'dynamodb',
|
||||||
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||||
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||||
|
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||||
|
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'octane' => [
|
||||||
|
'driver' => 'octane',
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Key Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
|
||||||
|
| stores, there might be other applications using the same cache. For
|
||||||
|
| that reason, you may prefix every cache key to avoid collisions.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,173 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Database Connection Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify which of the database connections below you wish
|
||||||
|
| to use as your default connection for database operations. This is
|
||||||
|
| the connection which will be utilized unless another connection
|
||||||
|
| is explicitly specified when you execute a query / statement.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('DB_CONNECTION', 'sqlite'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Database Connections
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Below are all of the database connections defined for your application.
|
||||||
|
| An example configuration is provided for each database system which
|
||||||
|
| is supported by Laravel. You're free to add / remove connections.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'connections' => [
|
||||||
|
|
||||||
|
'sqlite' => [
|
||||||
|
'driver' => 'sqlite',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||||
|
'prefix' => '',
|
||||||
|
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||||
|
'busy_timeout' => null,
|
||||||
|
'journal_mode' => null,
|
||||||
|
'synchronous' => null,
|
||||||
|
],
|
||||||
|
|
||||||
|
'mysql' => [
|
||||||
|
'driver' => 'mysql',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_PORT', '3306'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'unix_socket' => env('DB_SOCKET', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||||
|
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => true,
|
||||||
|
'engine' => null,
|
||||||
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
|
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
]) : [],
|
||||||
|
],
|
||||||
|
|
||||||
|
'mariadb' => [
|
||||||
|
'driver' => 'mariadb',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_PORT', '3306'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'unix_socket' => env('DB_SOCKET', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||||
|
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => true,
|
||||||
|
'engine' => null,
|
||||||
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
|
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
]) : [],
|
||||||
|
],
|
||||||
|
|
||||||
|
'pgsql' => [
|
||||||
|
'driver' => 'pgsql',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_PORT', '5432'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'search_path' => 'public',
|
||||||
|
'sslmode' => 'prefer',
|
||||||
|
],
|
||||||
|
|
||||||
|
'sqlsrv' => [
|
||||||
|
'driver' => 'sqlsrv',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', 'localhost'),
|
||||||
|
'port' => env('DB_PORT', '1433'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||||
|
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Migration Repository Table
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This table keeps track of all the migrations that have already run for
|
||||||
|
| your application. Using this information, we can determine which of
|
||||||
|
| the migrations on disk haven't actually been run on the database.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'migrations' => [
|
||||||
|
'table' => 'migrations',
|
||||||
|
'update_date_on_publish' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Redis Databases
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Redis is an open source, fast, and advanced key-value store that also
|
||||||
|
| provides a richer body of commands than a typical key-value system
|
||||||
|
| such as Memcached. You may define your connection settings here.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
|
||||||
|
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||||
|
|
||||||
|
'options' => [
|
||||||
|
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||||
|
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'default' => [
|
||||||
|
'url' => env('REDIS_URL'),
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'username' => env('REDIS_USERNAME'),
|
||||||
|
'password' => env('REDIS_PASSWORD'),
|
||||||
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
|
'database' => env('REDIS_DB', '0'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'cache' => [
|
||||||
|
'url' => env('REDIS_URL'),
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'username' => env('REDIS_USERNAME'),
|
||||||
|
'password' => env('REDIS_PASSWORD'),
|
||||||
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
|
'database' => env('REDIS_CACHE_DB', '1'),
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,380 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Maatwebsite\Excel\Excel;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Reader\Csv;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'exports' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Chunk size
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using FromQuery, the query is automatically chunked.
|
||||||
|
| Here you can specify how big the chunk should be.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'chunk_size' => 1000,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pre-calculate formulas during export
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
'pre_calculate_formulas' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Enable strict null comparison
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When enabling strict null comparison empty cells ('') will
|
||||||
|
| be added to the sheet.
|
||||||
|
*/
|
||||||
|
'strict_null_comparison' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CSV Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. delimiter, enclosure and line ending for CSV exports.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'csv' => [
|
||||||
|
'delimiter' => ',',
|
||||||
|
'enclosure' => '"',
|
||||||
|
'line_ending' => PHP_EOL,
|
||||||
|
'use_bom' => false,
|
||||||
|
'include_separator_line' => false,
|
||||||
|
'excel_compatibility' => false,
|
||||||
|
'output_encoding' => '',
|
||||||
|
'test_auto_detect' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Worksheet properties
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. default title, creator, subject,...
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'properties' => [
|
||||||
|
'creator' => '',
|
||||||
|
'lastModifiedBy' => '',
|
||||||
|
'title' => '',
|
||||||
|
'description' => '',
|
||||||
|
'subject' => '',
|
||||||
|
'keywords' => '',
|
||||||
|
'category' => '',
|
||||||
|
'manager' => '',
|
||||||
|
'company' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'imports' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Read Only
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with imports, you might only be interested in the
|
||||||
|
| data that the sheet exists. By default we ignore all styles,
|
||||||
|
| however if you want to do some logic based on style data
|
||||||
|
| you can enable it by setting read_only to false.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'read_only' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Ignore Empty
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with imports, you might be interested in ignoring
|
||||||
|
| rows that have null values or empty strings. By default rows
|
||||||
|
| containing empty strings or empty values are not ignored but can be
|
||||||
|
| ignored by enabling the setting ignore_empty to true.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'ignore_empty' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Heading Row Formatter
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure the heading row formatter.
|
||||||
|
| Available options: none|slug|custom
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'heading_row' => [
|
||||||
|
'formatter' => 'slug',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CSV Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. delimiter, enclosure and line ending for CSV imports.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'csv' => [
|
||||||
|
'delimiter' => null,
|
||||||
|
'enclosure' => '"',
|
||||||
|
'escape_character' => '\\',
|
||||||
|
'contiguous' => false,
|
||||||
|
'input_encoding' => Csv::GUESS_ENCODING,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Worksheet properties
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. default title, creator, subject,...
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'properties' => [
|
||||||
|
'creator' => '',
|
||||||
|
'lastModifiedBy' => '',
|
||||||
|
'title' => '',
|
||||||
|
'description' => '',
|
||||||
|
'subject' => '',
|
||||||
|
'keywords' => '',
|
||||||
|
'category' => '',
|
||||||
|
'manager' => '',
|
||||||
|
'company' => '',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cell Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure middleware that is executed on getting a cell value
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'cells' => [
|
||||||
|
'middleware' => [
|
||||||
|
//\Maatwebsite\Excel\Middleware\TrimCellValue::class,
|
||||||
|
//\Maatwebsite\Excel\Middleware\ConvertEmptyCellValuesToNull::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Extension detector
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure here which writer/reader type should be used when the package
|
||||||
|
| needs to guess the correct type based on the extension alone.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'extension_detector' => [
|
||||||
|
'xlsx' => Excel::XLSX,
|
||||||
|
'xlsm' => Excel::XLSX,
|
||||||
|
'xltx' => Excel::XLSX,
|
||||||
|
'xltm' => Excel::XLSX,
|
||||||
|
'xls' => Excel::XLS,
|
||||||
|
'xlt' => Excel::XLS,
|
||||||
|
'ods' => Excel::ODS,
|
||||||
|
'ots' => Excel::ODS,
|
||||||
|
'slk' => Excel::SLK,
|
||||||
|
'xml' => Excel::XML,
|
||||||
|
'gnumeric' => Excel::GNUMERIC,
|
||||||
|
'htm' => Excel::HTML,
|
||||||
|
'html' => Excel::HTML,
|
||||||
|
'csv' => Excel::CSV,
|
||||||
|
'tsv' => Excel::TSV,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| PDF Extension
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure here which Pdf driver should be used by default.
|
||||||
|
| Available options: Excel::MPDF | Excel::TCPDF | Excel::DOMPDF
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'pdf' => Excel::DOMPDF,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Value Binder
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| PhpSpreadsheet offers a way to hook into the process of a value being
|
||||||
|
| written to a cell. In there some assumptions are made on how the
|
||||||
|
| value should be formatted. If you want to change those defaults,
|
||||||
|
| you can implement your own default value binder.
|
||||||
|
|
|
||||||
|
| Possible value binders:
|
||||||
|
|
|
||||||
|
| [x] Maatwebsite\Excel\DefaultValueBinder::class
|
||||||
|
| [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class
|
||||||
|
| [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'value_binder' => [
|
||||||
|
'default' => Maatwebsite\Excel\DefaultValueBinder::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'cache' => [
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default cell caching driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By default PhpSpreadsheet keeps all cell values in memory, however when
|
||||||
|
| dealing with large files, this might result into memory issues. If you
|
||||||
|
| want to mitigate that, you can configure a cell caching driver here.
|
||||||
|
| When using the illuminate driver, it will store each value in the
|
||||||
|
| cache store. This can slow down the process, because it needs to
|
||||||
|
| store each value. You can use the "batch" store if you want to
|
||||||
|
| only persist to the store when the memory limit is reached.
|
||||||
|
|
|
||||||
|
| Drivers: memory|illuminate|batch
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'driver' => 'memory',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Batch memory caching
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with the "batch" caching driver, it will only
|
||||||
|
| persist to the store when the memory limit is reached.
|
||||||
|
| Here you can tweak the memory limit to your liking.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'batch' => [
|
||||||
|
'memory_limit' => 60000,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Illuminate cache
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using the "illuminate" caching driver, it will automatically use
|
||||||
|
| your default cache store. However if you prefer to have the cell
|
||||||
|
| cache on a separate store, you can configure the store name here.
|
||||||
|
| You can use any store defined in your cache config. When leaving
|
||||||
|
| at "null" it will use the default store.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'illuminate' => [
|
||||||
|
'store' => null,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Time-to-live (TTL)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The TTL of items written to cache. If you want to keep the items cached
|
||||||
|
| indefinitely, set this to null. Otherwise, set a number of seconds,
|
||||||
|
| a \DateInterval, or a callable.
|
||||||
|
|
|
||||||
|
| Allowable types: callable|\DateInterval|int|null
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'default_ttl' => 10800,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Transaction Handler
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By default the import is wrapped in a transaction. This is useful
|
||||||
|
| for when an import may fail and you want to retry it. With the
|
||||||
|
| transactions, the previous import gets rolled-back.
|
||||||
|
|
|
||||||
|
| You can disable the transaction handler by setting this to null.
|
||||||
|
| Or you can choose a custom made transaction handler here.
|
||||||
|
|
|
||||||
|
| Supported handlers: null|db
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'transactions' => [
|
||||||
|
'handler' => 'db',
|
||||||
|
'db' => [
|
||||||
|
'connection' => null,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'temporary_files' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Local Temporary Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When exporting and importing files, we use a temporary file, before
|
||||||
|
| storing reading or downloading. Here you can customize that path.
|
||||||
|
| permissions is an array with the permission flags for the directory (dir)
|
||||||
|
| and the create file (file).
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'local_path' => storage_path('framework/cache/laravel-excel'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Local Temporary Path Permissions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Permissions is an array with the permission flags for the directory (dir)
|
||||||
|
| and the create file (file).
|
||||||
|
| If omitted the default permissions of the filesystem will be used.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'local_permissions' => [
|
||||||
|
// 'dir' => 0755,
|
||||||
|
// 'file' => 0644,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Remote Temporary Disk
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with a multi server setup with queues in which you
|
||||||
|
| cannot rely on having a shared local temporary path, you might
|
||||||
|
| want to store the temporary file on a shared disk. During the
|
||||||
|
| queue executing, we'll retrieve the temporary file from that
|
||||||
|
| location instead. When left to null, it will always use
|
||||||
|
| the local path. This setting only has effect when using
|
||||||
|
| in conjunction with queued imports and exports.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'remote_disk' => null,
|
||||||
|
'remote_prefix' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Force Resync
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with a multi server setup as above, it's possible
|
||||||
|
| for the clean up that occurs after entire queue has been run to only
|
||||||
|
| cleanup the server that the last AfterImportJob runs on. The rest of the server
|
||||||
|
| would still have the local temporary file stored on it. In this case your
|
||||||
|
| local storage limits can be exceeded and future imports won't be processed.
|
||||||
|
| To mitigate this you can set this config value to be true, so that after every
|
||||||
|
| queued chunk is processed the local temporary file is deleted on the server that
|
||||||
|
| processed it.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'force_resync_remote' => null,
|
||||||
|
],
|
||||||
|
];
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Filesystem Disk
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the default filesystem disk that should be used
|
||||||
|
| by the framework. The "local" disk, as well as a variety of cloud
|
||||||
|
| based disks are available to your application for file storage.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('FILESYSTEM_DISK', 'local'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Filesystem Disks
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Below you may configure as many filesystem disks as necessary, and you
|
||||||
|
| may even configure multiple disks for the same driver. Examples for
|
||||||
|
| most supported storage drivers are configured here for reference.
|
||||||
|
|
|
||||||
|
| Supported drivers: "local", "ftp", "sftp", "s3"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'disks' => [
|
||||||
|
|
||||||
|
'local' => [
|
||||||
|
'driver' => 'local',
|
||||||
|
'root' => storage_path('app/private'),
|
||||||
|
'serve' => true,
|
||||||
|
'throw' => false,
|
||||||
|
'report' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'public' => [
|
||||||
|
'driver' => 'local',
|
||||||
|
'root' => storage_path('app/public'),
|
||||||
|
'url' => env('APP_URL').'/storage',
|
||||||
|
'visibility' => 'public',
|
||||||
|
'throw' => false,
|
||||||
|
'report' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
's3' => [
|
||||||
|
'driver' => 's3',
|
||||||
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||||
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
|
'region' => env('AWS_DEFAULT_REGION'),
|
||||||
|
'bucket' => env('AWS_BUCKET'),
|
||||||
|
'url' => env('AWS_URL'),
|
||||||
|
'endpoint' => env('AWS_ENDPOINT'),
|
||||||
|
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||||
|
'throw' => false,
|
||||||
|
'report' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Symbolic Links
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure the symbolic links that will be created when the
|
||||||
|
| `storage:link` Artisan command is executed. The array keys should be
|
||||||
|
| the locations of the links and the values should be their targets.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'links' => [
|
||||||
|
public_path('storage') => storage_path('app/public'),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Monolog\Handler\NullHandler;
|
||||||
|
use Monolog\Handler\StreamHandler;
|
||||||
|
use Monolog\Handler\SyslogUdpHandler;
|
||||||
|
use Monolog\Processor\PsrLogMessageProcessor;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Log Channel
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option defines the default log channel that is utilized to write
|
||||||
|
| messages to your logs. The value provided here should match one of
|
||||||
|
| the channels present in the list of "channels" configured below.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('LOG_CHANNEL', 'stack'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Deprecations Log Channel
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the log channel that should be used to log warnings
|
||||||
|
| regarding deprecated PHP and library features. This allows you to get
|
||||||
|
| your application ready for upcoming major versions of dependencies.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'deprecations' => [
|
||||||
|
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
|
||||||
|
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Channels
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure the log channels for your application. Laravel
|
||||||
|
| utilizes the Monolog PHP logging library, which includes a variety
|
||||||
|
| of powerful log handlers and formatters that you're free to use.
|
||||||
|
|
|
||||||
|
| Available drivers: "single", "daily", "slack", "syslog",
|
||||||
|
| "errorlog", "monolog", "custom", "stack"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'channels' => [
|
||||||
|
|
||||||
|
'stack' => [
|
||||||
|
'driver' => 'stack',
|
||||||
|
'channels' => explode(',', env('LOG_STACK', 'single')),
|
||||||
|
'ignore_exceptions' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'single' => [
|
||||||
|
'driver' => 'single',
|
||||||
|
'path' => storage_path('logs/laravel.log'),
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'daily' => [
|
||||||
|
'driver' => 'daily',
|
||||||
|
'path' => storage_path('logs/laravel.log'),
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'days' => env('LOG_DAILY_DAYS', 14),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'slack' => [
|
||||||
|
'driver' => 'slack',
|
||||||
|
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||||
|
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
|
||||||
|
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
|
||||||
|
'level' => env('LOG_LEVEL', 'critical'),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'papertrail' => [
|
||||||
|
'driver' => 'monolog',
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
|
||||||
|
'handler_with' => [
|
||||||
|
'host' => env('PAPERTRAIL_URL'),
|
||||||
|
'port' => env('PAPERTRAIL_PORT'),
|
||||||
|
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
|
||||||
|
],
|
||||||
|
'processors' => [PsrLogMessageProcessor::class],
|
||||||
|
],
|
||||||
|
|
||||||
|
'stderr' => [
|
||||||
|
'driver' => 'monolog',
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'handler' => StreamHandler::class,
|
||||||
|
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||||
|
'with' => [
|
||||||
|
'stream' => 'php://stderr',
|
||||||
|
],
|
||||||
|
'processors' => [PsrLogMessageProcessor::class],
|
||||||
|
],
|
||||||
|
|
||||||
|
'syslog' => [
|
||||||
|
'driver' => 'syslog',
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'errorlog' => [
|
||||||
|
'driver' => 'errorlog',
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'null' => [
|
||||||
|
'driver' => 'monolog',
|
||||||
|
'handler' => NullHandler::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'emergency' => [
|
||||||
|
'path' => storage_path('logs/laravel.log'),
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Mailer
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default mailer that is used to send all email
|
||||||
|
| messages unless another mailer is explicitly specified when sending
|
||||||
|
| the message. All additional mailers can be configured within the
|
||||||
|
| "mailers" array. Examples of each type of mailer are provided.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('MAIL_MAILER', 'log'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Mailer Configurations
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure all of the mailers used by your application plus
|
||||||
|
| their respective settings. Several examples have been configured for
|
||||||
|
| you and you are free to add your own as your application requires.
|
||||||
|
|
|
||||||
|
| Laravel supports a variety of mail "transport" drivers that can be used
|
||||||
|
| when delivering an email. You may specify which one you're using for
|
||||||
|
| your mailers below. You may also add additional mailers if needed.
|
||||||
|
|
|
||||||
|
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
|
||||||
|
| "postmark", "resend", "log", "array",
|
||||||
|
| "failover", "roundrobin"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'mailers' => [
|
||||||
|
|
||||||
|
'smtp' => [
|
||||||
|
'transport' => 'smtp',
|
||||||
|
'scheme' => env('MAIL_SCHEME'),
|
||||||
|
'url' => env('MAIL_URL'),
|
||||||
|
'host' => env('MAIL_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('MAIL_PORT', 2525),
|
||||||
|
'username' => env('MAIL_USERNAME'),
|
||||||
|
'password' => env('MAIL_PASSWORD'),
|
||||||
|
'timeout' => null,
|
||||||
|
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
|
||||||
|
],
|
||||||
|
|
||||||
|
'ses' => [
|
||||||
|
'transport' => 'ses',
|
||||||
|
],
|
||||||
|
|
||||||
|
'postmark' => [
|
||||||
|
'transport' => 'postmark',
|
||||||
|
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
|
||||||
|
// 'client' => [
|
||||||
|
// 'timeout' => 5,
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
|
||||||
|
'resend' => [
|
||||||
|
'transport' => 'resend',
|
||||||
|
],
|
||||||
|
|
||||||
|
'sendmail' => [
|
||||||
|
'transport' => 'sendmail',
|
||||||
|
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'log' => [
|
||||||
|
'transport' => 'log',
|
||||||
|
'channel' => env('MAIL_LOG_CHANNEL'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'array' => [
|
||||||
|
'transport' => 'array',
|
||||||
|
],
|
||||||
|
|
||||||
|
'failover' => [
|
||||||
|
'transport' => 'failover',
|
||||||
|
'mailers' => [
|
||||||
|
'smtp',
|
||||||
|
'log',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'roundrobin' => [
|
||||||
|
'transport' => 'roundrobin',
|
||||||
|
'mailers' => [
|
||||||
|
'ses',
|
||||||
|
'postmark',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Global "From" Address
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| You may wish for all emails sent by your application to be sent from
|
||||||
|
| the same address. Here you may specify a name and address that is
|
||||||
|
| used globally for all emails that are sent by your application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'from' => [
|
||||||
|
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
||||||
|
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Queue Connection Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Laravel's queue supports a variety of backends via a single, unified
|
||||||
|
| API, giving you convenient access to each backend using identical
|
||||||
|
| syntax for each. The default queue connection is defined below.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('QUEUE_CONNECTION', 'database'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Connections
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure the connection options for every queue backend
|
||||||
|
| used by your application. An example configuration is provided for
|
||||||
|
| each backend supported by Laravel. You're also free to add more.
|
||||||
|
|
|
||||||
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'connections' => [
|
||||||
|
|
||||||
|
'sync' => [
|
||||||
|
'driver' => 'sync',
|
||||||
|
],
|
||||||
|
|
||||||
|
'database' => [
|
||||||
|
'driver' => 'database',
|
||||||
|
'connection' => env('DB_QUEUE_CONNECTION'),
|
||||||
|
'table' => env('DB_QUEUE_TABLE', 'jobs'),
|
||||||
|
'queue' => env('DB_QUEUE', 'default'),
|
||||||
|
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
|
||||||
|
'after_commit' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'beanstalkd' => [
|
||||||
|
'driver' => 'beanstalkd',
|
||||||
|
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
|
||||||
|
'queue' => env('BEANSTALKD_QUEUE', 'default'),
|
||||||
|
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
|
||||||
|
'block_for' => 0,
|
||||||
|
'after_commit' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'sqs' => [
|
||||||
|
'driver' => 'sqs',
|
||||||
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||||
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
|
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||||
|
'queue' => env('SQS_QUEUE', 'default'),
|
||||||
|
'suffix' => env('SQS_SUFFIX'),
|
||||||
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||||
|
'after_commit' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
'driver' => 'redis',
|
||||||
|
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
|
||||||
|
'queue' => env('REDIS_QUEUE', 'default'),
|
||||||
|
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
|
||||||
|
'block_for' => null,
|
||||||
|
'after_commit' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Job Batching
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following options configure the database and table that store job
|
||||||
|
| batching information. These options can be updated to any database
|
||||||
|
| connection and table which has been defined by your application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'batching' => [
|
||||||
|
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||||
|
'table' => 'job_batches',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Failed Queue Jobs
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These options configure the behavior of failed queue job logging so you
|
||||||
|
| can control how and where failed jobs are stored. Laravel ships with
|
||||||
|
| support for storing failed jobs in a simple file or in a database.
|
||||||
|
|
|
||||||
|
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'failed' => [
|
||||||
|
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
|
||||||
|
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||||
|
'table' => 'failed_jobs',
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Laravel\Sanctum\Sanctum;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Stateful Domains
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Requests from the following domains / hosts will receive stateful API
|
||||||
|
| authentication cookies. Typically, these should include your local
|
||||||
|
| and production domains which access your API via a frontend SPA.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
|
||||||
|
'%s%s',
|
||||||
|
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
|
||||||
|
Sanctum::currentApplicationUrlWithPort()
|
||||||
|
))),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Sanctum Guards
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This array contains the authentication guards that will be checked when
|
||||||
|
| Sanctum is trying to authenticate a request. If none of these guards
|
||||||
|
| are able to authenticate the request, Sanctum will use the bearer
|
||||||
|
| token that's present on an incoming request for authentication.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'guard' => ['web'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Expiration Minutes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value controls the number of minutes until an issued token will be
|
||||||
|
| considered expired. This will override any values set in the token's
|
||||||
|
| "expires_at" attribute, but first-party sessions are not affected.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'expiration' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Token Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Sanctum can prefix new tokens in order to take advantage of numerous
|
||||||
|
| security scanning initiatives maintained by open source platforms
|
||||||
|
| that notify developers if they commit tokens into repositories.
|
||||||
|
|
|
||||||
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Sanctum Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When authenticating your first-party SPA with Sanctum you may need to
|
||||||
|
| customize some of the middleware Sanctum uses while processing the
|
||||||
|
| request. You may change the middleware listed below as required.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
|
||||||
|
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||||
|
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Third Party Services
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This file is for storing the credentials for third party services such
|
||||||
|
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||||
|
| location for this type of information, allowing packages to have
|
||||||
|
| a conventional file to locate the various service credentials.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'postmark' => [
|
||||||
|
'token' => env('POSTMARK_TOKEN'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'ses' => [
|
||||||
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||||
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'resend' => [
|
||||||
|
'key' => env('RESEND_KEY'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'slack' => [
|
||||||
|
'notifications' => [
|
||||||
|
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
||||||
|
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,217 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Session Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option determines the default session driver that is utilized for
|
||||||
|
| incoming requests. Laravel supports a variety of storage options to
|
||||||
|
| persist session data. Database storage is a great default choice.
|
||||||
|
|
|
||||||
|
| Supported: "file", "cookie", "database", "apc",
|
||||||
|
| "memcached", "redis", "dynamodb", "array"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'driver' => env('SESSION_DRIVER', 'database'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Lifetime
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the number of minutes that you wish the session
|
||||||
|
| to be allowed to remain idle before it expires. If you want them
|
||||||
|
| to expire immediately when the browser is closed then you may
|
||||||
|
| indicate that via the expire_on_close configuration option.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'lifetime' => (int) env('SESSION_LIFETIME', 120),
|
||||||
|
|
||||||
|
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Encryption
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to easily specify that all of your session data
|
||||||
|
| should be encrypted before it's stored. All encryption is performed
|
||||||
|
| automatically by Laravel and you may use the session like normal.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'encrypt' => env('SESSION_ENCRYPT', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session File Location
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When utilizing the "file" session driver, the session files are placed
|
||||||
|
| on disk. The default storage location is defined here; however, you
|
||||||
|
| are free to provide another location where they should be stored.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'files' => storage_path('framework/sessions'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Database Connection
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using the "database" or "redis" session drivers, you may specify a
|
||||||
|
| connection that should be used to manage these sessions. This should
|
||||||
|
| correspond to a connection in your database configuration options.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'connection' => env('SESSION_CONNECTION'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Database Table
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using the "database" session driver, you may specify the table to
|
||||||
|
| be used to store sessions. Of course, a sensible default is defined
|
||||||
|
| for you; however, you're welcome to change this to another table.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'table' => env('SESSION_TABLE', 'sessions'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Cache Store
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using one of the framework's cache driven session backends, you may
|
||||||
|
| define the cache store which should be used to store the session data
|
||||||
|
| between requests. This must match one of your defined cache stores.
|
||||||
|
|
|
||||||
|
| Affects: "apc", "dynamodb", "memcached", "redis"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'store' => env('SESSION_STORE'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Sweeping Lottery
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Some session drivers must manually sweep their storage location to get
|
||||||
|
| rid of old sessions from storage. Here are the chances that it will
|
||||||
|
| happen on a given request. By default, the odds are 2 out of 100.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'lottery' => [2, 100],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Cookie Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may change the name of the session cookie that is created by
|
||||||
|
| the framework. Typically, you should not need to change this value
|
||||||
|
| since doing so does not grant a meaningful security improvement.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cookie' => env(
|
||||||
|
'SESSION_COOKIE',
|
||||||
|
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||||
|
),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Cookie Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The session cookie path determines the path for which the cookie will
|
||||||
|
| be regarded as available. Typically, this will be the root path of
|
||||||
|
| your application, but you're free to change this when necessary.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'path' => env('SESSION_PATH', '/'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Session Cookie Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the domain and subdomains the session cookie is
|
||||||
|
| available to. By default, the cookie will be available to the root
|
||||||
|
| domain and all subdomains. Typically, this shouldn't be changed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'domain' => env('SESSION_DOMAIN'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| HTTPS Only Cookies
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By setting this option to true, session cookies will only be sent back
|
||||||
|
| to the server if the browser has a HTTPS connection. This will keep
|
||||||
|
| the cookie from being sent to you when it can't be done securely.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| HTTP Access Only
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Setting this value to true will prevent JavaScript from accessing the
|
||||||
|
| value of the cookie and the cookie will only be accessible through
|
||||||
|
| the HTTP protocol. It's unlikely you should disable this option.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'http_only' => env('SESSION_HTTP_ONLY', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Same-Site Cookies
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option determines how your cookies behave when cross-site requests
|
||||||
|
| take place, and can be used to mitigate CSRF attacks. By default, we
|
||||||
|
| will set this value to "lax" to permit secure cross-site requests.
|
||||||
|
|
|
||||||
|
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
||||||
|
|
|
||||||
|
| Supported: "lax", "strict", "none", null
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'same_site' => env('SESSION_SAME_SITE', 'lax'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Partitioned Cookies
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Setting this value to true will tie the cookie to the top-level site for
|
||||||
|
| a cross-site context. Partitioned cookies are accepted by the browser
|
||||||
|
| when flagged "secure" and the Same-Site attribute is set to "none".
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,267 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Theme
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| The theme to use for SweetAlert2 popups.
|
||||||
|
| Available themes: dark, minimal, borderless, bootstrap-4, material-ui, wordpress-admin, bulma.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'theme' => env('SWEET_ALERT_THEME', 'default'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CDN LINK
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| By default SweetAlert2 use its local sweetalert.all.js
|
||||||
|
| file.
|
||||||
|
| However, you can use its cdn if you want.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cdn' => env('SWEET_ALERT_CDN'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Always load the sweetalert.all.js
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| There might be situations where you will always want the sweet alert
|
||||||
|
| js package to be there for you. (for eg. you might use it heavily to
|
||||||
|
| show notifications or you might want to use the native js) then this
|
||||||
|
| might be handy.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'alwaysLoadJS' => env('SWEET_ALERT_ALWAYS_LOAD_JS', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Never load the sweetalert.all.js
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| If you want to handle the sweet alert js package by yourself
|
||||||
|
| (for eg. you might want to use laravel mix) then this can be
|
||||||
|
| handy.
|
||||||
|
|
|
||||||
|
| alwaysLoadJs = true & neverLoadJs = true => js will not be loaded
|
||||||
|
| alwaysLoadJs = true & neverLoadJs = false => js will be loaded
|
||||||
|
| alwaysLoadJs = false & neverLoadJs = false => js will be loaded when
|
||||||
|
| you set alert/toast by using the facade/helper functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'neverLoadJS' => env('SWEET_ALERT_NEVER_LOAD_JS', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| AutoClose Timer
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is for the all Modal windows.
|
||||||
|
| For specific modal just use the autoClose() helper method.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timer' => env('SWEET_ALERT_TIMER', 5000),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Width
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Modal window width, including paddings (box-sizing: border-box).
|
||||||
|
| Can be in px or %.
|
||||||
|
| The default width is 32rem.
|
||||||
|
| This is for the all Modal windows.
|
||||||
|
| for particular modal just use the width() helper method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'width' => env('SWEET_ALERT_WIDTH', '32rem'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Height Auto
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| By default, SweetAlert2 sets html's and body's CSS height to auto !important.
|
||||||
|
| If this behavior isn't compatible with your project's layout,
|
||||||
|
| set heightAuto to false.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'height_auto' => env('SWEET_ALERT_HEIGHT_AUTO', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Padding
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Modal window padding.
|
||||||
|
| Can be in px or %.
|
||||||
|
| The default padding is 1.25rem.
|
||||||
|
| This is for the all Modal windows.
|
||||||
|
| for particular modal just use the padding() helper method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'padding' => env('SWEET_ALERT_PADDING', '1.25rem'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Background
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Modal window background
|
||||||
|
| (CSS background property).
|
||||||
|
| The default background is '#fff'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'background' => env('SWEET_ALERT_BACKGROUND', '#fff'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Animation
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Custom animation with [Animate.css](https://daneden.github.io/animate.css/)
|
||||||
|
| If set to false, modal CSS animation will be use default ones.
|
||||||
|
| For specific modal just use the animation() helper method.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'animation' => [
|
||||||
|
'enable' => env('SWEET_ALERT_ANIMATION_ENABLE', false),
|
||||||
|
],
|
||||||
|
|
||||||
|
'animatecss' => env('SWEET_ALERT_ANIMATECSS', 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ShowConfirmButton
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| If set to false, a "Confirm"-button will not be shown.
|
||||||
|
| It can be useful when you're using custom HTML description.
|
||||||
|
| This is for the all Modal windows.
|
||||||
|
| For specific modal just use the showConfirmButton() helper method.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'show_confirm_button' => env('SWEET_ALERT_CONFIRM_BUTTON', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ShowCloseButton
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| If set to true, a "Close"-button will be shown,
|
||||||
|
| which the user can click on to dismiss the modal.
|
||||||
|
| This is for the all Modal windows.
|
||||||
|
| For specific modal just use the showCloseButton() helper method.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'show_close_button' => env('SWEET_ALERT_CLOSE_BUTTON', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|-----------------------------------------------------------------------
|
||||||
|
| Confirm/Cancel Button Text
|
||||||
|
|-----------------------------------------------------------------------
|
||||||
|
| Change the default text of the modal buttons.
|
||||||
|
| The texts translations will be handled by Laravel at runtime.
|
||||||
|
| This is for the all Modal windows.
|
||||||
|
| For specific modal just use the confirmButtonText() and
|
||||||
|
| cancelButtonText() helper methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'button_text' => [
|
||||||
|
'confirm' => env('SWEET_ALERT_CONFIRM_BUTTON_TEXT', 'OK'),
|
||||||
|
'cancel' => env('SWEET_ALERT_CANCEL_BUTTON_TEXT', 'Cancel'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Toast position
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Modal window or toast position, can be 'top',
|
||||||
|
| 'top-start', 'top-end', 'center', 'center-start',
|
||||||
|
| 'center-end', 'bottom', 'bottom-start', or 'bottom-end'.
|
||||||
|
| For specific modal just use the position() helper method.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'toast_position' => env('SWEET_ALERT_TOAST_POSITION', 'top-end'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Progress Bar
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| If set to true, a progress bar at the bottom of a popup will be shown.
|
||||||
|
| It can be useful with toasts.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timer_progress_bar' => env('SWEET_ALERT_TIMER_PROGRESS_BAR', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Modal window or toast, config for the Middleware
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
|
||||||
|
'autoClose' => env('SWEET_ALERT_MIDDLEWARE_AUTO_CLOSE', false),
|
||||||
|
|
||||||
|
'toast_position' => env('SWEET_ALERT_MIDDLEWARE_TOAST_POSITION', 'top-end'),
|
||||||
|
|
||||||
|
'toast_close_button' => env('SWEET_ALERT_MIDDLEWARE_TOAST_CLOSE_BUTTON', true),
|
||||||
|
|
||||||
|
'timer' => env('SWEET_ALERT_MIDDLEWARE_ALERT_CLOSE_TIME', 6000),
|
||||||
|
|
||||||
|
'auto_display_error_messages' => env('SWEET_ALERT_AUTO_DISPLAY_ERROR_MESSAGES', true),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Custom Class
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| A custom CSS class for the modal:
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'customClass' => [
|
||||||
|
|
||||||
|
'container' => env('SWEET_ALERT_CONTAINER_CLASS'),
|
||||||
|
'popup' => env('SWEET_ALERT_POPUP_CLASS'),
|
||||||
|
'header' => env('SWEET_ALERT_HEADER_CLASS'),
|
||||||
|
'title' => env('SWEET_ALERT_TITLE_CLASS'),
|
||||||
|
'closeButton' => env('SWEET_ALERT_CLOSE_BUTTON_CLASS'),
|
||||||
|
'icon' => env('SWEET_ALERT_ICON_CLASS'),
|
||||||
|
'image' => env('SWEET_ALERT_IMAGE_CLASS'),
|
||||||
|
'content' => env('SWEET_ALERT_CONTENT_CLASS'),
|
||||||
|
'input' => env('SWEET_ALERT_INPUT_CLASS'),
|
||||||
|
'actions' => env('SWEET_ALERT_ACTIONS_CLASS'),
|
||||||
|
'confirmButton' => env('SWEET_ALERT_CONFIRM_BUTTON_CLASS'),
|
||||||
|
'cancelButton' => env('SWEET_ALERT_CANCEL_BUTTON_CLASS'),
|
||||||
|
'footer' => env('SWEET_ALERT_FOOTER_CLASS'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| confirmDelete
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| customize the configuration options of the confirmation popup.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'confirm_delete_confirm_button_text' => env('SWEET_ALERT_CONFIRM_DELETE_CONFIRM_BUTTON_TEXT', 'Yes, delete it!'),
|
||||||
|
'confirm_delete_confirm_button_color' => env('SWEET_ALERT_CONFIRM_DELETE_CONFIRM_BUTTON_COLOR'),
|
||||||
|
'confirm_delete_cancel_button_color' => env('SWEET_ALERT_CONFIRM_DELETE_CANCEL_BUTTON_COLOR', '#d33'),
|
||||||
|
'confirm_delete_cancel_button_text' => env('SWEET_ALERT_CONFIRM_DELETE_CANCEL_BUTTON_TEXT', 'Cancel'),
|
||||||
|
'confirm_delete_show_cancel_button' => env('SWEET_ALERT_CONFIRM_DELETE_SHOW_CANCEL_BUTTON', true),
|
||||||
|
'confirm_delete_show_close_button' => env('SWEET_ALERT_CONFIRM_DELETE_SHOW_CLOSE_BUTTON', false),
|
||||||
|
'confirm_delete_icon' => env('SWEET_ALERT_CONFIRM_DELETE_ICON', 'warning'),
|
||||||
|
'confirm_delete_show_loader_on_confirm' => env('SWEET_ALERT_CONFIRM_DELETE_SHOW_LOADER_ON_CONFIRM', true),
|
||||||
|
|
||||||
|
|
||||||
|
];
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue