Initial commit from local Laravel project
This commit is contained in:
commit
d65db6142c
|
@ -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,65 @@
|
||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
|
PHP_CLI_SERVER_WORKERS=4
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=sqlite
|
||||||
|
# DB_HOST=127.0.0.1
|
||||||
|
# DB_PORT=3306
|
||||||
|
# DB_DATABASE=laravel
|
||||||
|
# DB_USERNAME=root
|
||||||
|
# DB_PASSWORD=
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_SCHEME=null
|
||||||
|
MAIL_HOST=127.0.0.1
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
|
@ -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,61 @@
|
||||||
|
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## About Laravel
|
||||||
|
|
||||||
|
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||||
|
|
||||||
|
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||||
|
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||||
|
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||||
|
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||||
|
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||||
|
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||||
|
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||||
|
|
||||||
|
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||||
|
|
||||||
|
## Learning Laravel
|
||||||
|
|
||||||
|
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||||
|
|
||||||
|
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||||
|
|
||||||
|
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||||
|
|
||||||
|
## Laravel Sponsors
|
||||||
|
|
||||||
|
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||||
|
|
||||||
|
### Premium Partners
|
||||||
|
|
||||||
|
- **[Vehikl](https://vehikl.com/)**
|
||||||
|
- **[Tighten Co.](https://tighten.co)**
|
||||||
|
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||||
|
- **[64 Robots](https://64robots.com)**
|
||||||
|
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||||
|
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||||
|
- **[Redberry](https://redberry.international/laravel-development/)**
|
||||||
|
- **[Active Logic](https://activelogic.com)**
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||||
|
|
||||||
|
## Security Vulnerabilities
|
||||||
|
|
||||||
|
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Alternatif;
|
||||||
|
use App\Models\Mapel;
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class AlternatifController extends Controller
|
||||||
|
{
|
||||||
|
public function alternatif()
|
||||||
|
{
|
||||||
|
$mapels = Mapel::where('kategori', 'Mata Pelajaran Pilihan')->get();
|
||||||
|
$kurikulums = Kurikulum::all();
|
||||||
|
$alternatifs = Alternatif::with('mapels')->get();
|
||||||
|
return view('admin.alternatif', compact('alternatifs','mapels', 'kurikulums'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahalternatif(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
'mapel_id' => 'required|array|min:1',
|
||||||
|
'mapel_id.*' => 'exists:mapels,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cek duplikat nama
|
||||||
|
$duplikatNama = Alternatif::where('nama', $request->nama)
|
||||||
|
->where('kurikulum_id', $request->kurikulum_id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Nama alternatif sudah ada dalam kurikulum yang sama.');
|
||||||
|
return redirect()->back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Simpan alternatif dulu
|
||||||
|
$alternatif = new Alternatif();
|
||||||
|
|
||||||
|
$alternatif->nama = $request->nama;
|
||||||
|
$alternatif->kurikulum_id = $request->kurikulum_id;
|
||||||
|
|
||||||
|
if ($alternatif->save()) {
|
||||||
|
$alternatif->mapels()->sync($request->mapel_id); // sinkronisasi setelah tersimpan
|
||||||
|
toastr()->success('Alternatif berhasil ditambahkan');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan alternatif');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('alternatif');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatealternatif(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
'mapel_id' => 'required|array|min:1',
|
||||||
|
'mapel_id.*' => 'exists:mapels,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$alternatif = Alternatif::findOrFail($id);
|
||||||
|
|
||||||
|
// Cek duplikat nama (kecuali milik sendiri)
|
||||||
|
$duplikatNama = Alternatif::where('nama', $request->nama)
|
||||||
|
->where('kurikulum_id', $request->kurikulum_id)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Nama alternatif sudah ada dalam kurikulum yang sama.');
|
||||||
|
return redirect()->back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Update data
|
||||||
|
|
||||||
|
$alternatif->nama = $request->nama;
|
||||||
|
$alternatif->kurikulum_id = $request->kurikulum_id;
|
||||||
|
|
||||||
|
if ($alternatif->save()) {
|
||||||
|
$alternatif->mapels()->sync($request->mapel_id);
|
||||||
|
toastr()->success('Alternatif berhasil diperbarui');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui alternatif');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('alternatif')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapusalternatif($id)
|
||||||
|
{
|
||||||
|
$alternatif = Alternatif::findOrFail($id);
|
||||||
|
if ($alternatif->delete()) {
|
||||||
|
toastr()->success('Alternatif berhasil dihapus');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menghapus alternatif');
|
||||||
|
}
|
||||||
|
return redirect()->route('alternatif');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadalternatif()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$alternatifs = Alternatif::all();
|
||||||
|
$pdf = Pdf::loadView('admin.alternatifpdf', compact('alternatifs'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_alternatif.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Auth\LoginRequest;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class AuthenticatedSessionController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the login view.
|
||||||
|
*/
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('auth.login');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming authentication request.
|
||||||
|
*/
|
||||||
|
public function store(LoginRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->authenticate();
|
||||||
|
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
if($request->user()->usertype == 'admin')
|
||||||
|
{
|
||||||
|
return redirect('admin/dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->intended(route('dashboard'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy an authenticated session.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
Auth::guard('web')->logout();
|
||||||
|
|
||||||
|
$request->session()->invalidate();
|
||||||
|
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class ConfirmablePasswordController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show the confirm password view.
|
||||||
|
*/
|
||||||
|
public function show(): View
|
||||||
|
{
|
||||||
|
return view('auth.confirm-password');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm the user's password.
|
||||||
|
*/
|
||||||
|
public function store(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
if (! Auth::guard('web')->validate([
|
||||||
|
'email' => $request->user()->email,
|
||||||
|
'password' => $request->password,
|
||||||
|
])) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'password' => __('auth.password'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->session()->put('auth.password_confirmed_at', time());
|
||||||
|
|
||||||
|
return redirect()->intended(route('dashboard', absolute: false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class EmailVerificationNotificationController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send a new email verification notification.
|
||||||
|
*/
|
||||||
|
public function store(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
if ($request->user()->hasVerifiedEmail()) {
|
||||||
|
return redirect()->intended(route('dashboard', absolute: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->user()->sendEmailVerificationNotification();
|
||||||
|
|
||||||
|
return back()->with('status', 'verification-link-sent');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class EmailVerificationPromptController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the email verification prompt.
|
||||||
|
*/
|
||||||
|
public function __invoke(Request $request): RedirectResponse|View
|
||||||
|
{
|
||||||
|
return $request->user()->hasVerifiedEmail()
|
||||||
|
? redirect()->intended(route('dashboard', absolute: false))
|
||||||
|
: view('auth.verify-email');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Events\PasswordReset;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Password;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Validation\Rules;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class NewPasswordController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the password reset view.
|
||||||
|
*/
|
||||||
|
public function create(Request $request): View
|
||||||
|
{
|
||||||
|
return view('auth.reset-password', ['request' => $request]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming new password request.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
public function store(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'token' => ['required'],
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Here we will attempt to reset the user's password. If it is successful we
|
||||||
|
// will update the password on an actual user model and persist it to the
|
||||||
|
// database. Otherwise we will parse the error and return the response.
|
||||||
|
$status = Password::reset(
|
||||||
|
$request->only('email', 'password', 'password_confirmation', 'token'),
|
||||||
|
function (User $user) use ($request) {
|
||||||
|
$user->forceFill([
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
'remember_token' => Str::random(60),
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
event(new PasswordReset($user));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// If the password was successfully reset, we will redirect the user back to
|
||||||
|
// the application's home authenticated view. If there is an error we can
|
||||||
|
// redirect them back to where they came from with their error message.
|
||||||
|
return $status == Password::PASSWORD_RESET
|
||||||
|
? redirect()->route('login')->with('status', __($status))
|
||||||
|
: back()->withInput($request->only('email'))
|
||||||
|
->withErrors(['email' => __($status)]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
|
|
||||||
|
class PasswordController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Update the user's password.
|
||||||
|
*/
|
||||||
|
public function update(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$validated = $request->validateWithBag('updatePassword', [
|
||||||
|
'current_password' => ['required', 'current_password'],
|
||||||
|
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$request->user()->update([
|
||||||
|
'password' => Hash::make($validated['password']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with('status', 'password-updated');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Password;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class PasswordResetLinkController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the password reset link request view.
|
||||||
|
*/
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('auth.forgot-password');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming password reset link request.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
public function store(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// We will send the password reset link to this user. Once we have attempted
|
||||||
|
// to send the link, we will examine the response then see the message we
|
||||||
|
// need to show to the user. Finally, we'll send out a proper response.
|
||||||
|
$status = Password::sendResetLink(
|
||||||
|
$request->only('email')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $status == Password::RESET_LINK_SENT
|
||||||
|
? back()->with('status', __($status))
|
||||||
|
: back()->withInput($request->only('email'))
|
||||||
|
->withErrors(['email' => __($status)]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Events\Registered;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\Rules;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class RegisteredUserController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the registration view.
|
||||||
|
*/
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('auth.register');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming registration request.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
public function store(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||||
|
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = User::create([
|
||||||
|
'name' => $request->name,
|
||||||
|
'email' => $request->email,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
]);
|
||||||
|
|
||||||
|
event(new Registered($user));
|
||||||
|
|
||||||
|
Auth::login($user);
|
||||||
|
|
||||||
|
return redirect(route('dashboard', absolute: false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Auth\Events\Verified;
|
||||||
|
use Illuminate\Foundation\Auth\EmailVerificationRequest;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
|
class VerifyEmailController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Mark the authenticated user's email address as verified.
|
||||||
|
*/
|
||||||
|
public function __invoke(EmailVerificationRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
if ($request->user()->hasVerifiedEmail()) {
|
||||||
|
return redirect()->intended(route('dashboard', absolute: false).'?verified=1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->user()->markEmailAsVerified()) {
|
||||||
|
event(new Verified($request->user()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->intended(route('dashboard', absolute: false).'?verified=1');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
abstract class Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Crip;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class CripsController extends Controller
|
||||||
|
{
|
||||||
|
public function crips()
|
||||||
|
{
|
||||||
|
$crips = Crip::all();
|
||||||
|
return view('admin.crips', compact('crips'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahcrips(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required|string|unique:crips,nama',
|
||||||
|
'nilai' => 'required|integer|unique:crips,nilai',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
$nilai = $request->input('nilai');
|
||||||
|
|
||||||
|
// Cek apakah ada crips dengan nama atau nilai yang duplikat
|
||||||
|
$duplikat = Crip::where('nama', $nama)->orWhere('nilai', $nilai)->exists();
|
||||||
|
|
||||||
|
if ($duplikat) {
|
||||||
|
toastr()->error('Nama atau nilai tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$crip = new Crip();
|
||||||
|
$crip->nama = $nama;
|
||||||
|
$crip->nilai = $nilai;
|
||||||
|
|
||||||
|
if ($crip->save()) {
|
||||||
|
toastr()->success('Data crips berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data crips.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('crips');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function updatecrips(Request $request, $id)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required|string|unique:crips,nama,' . $id,
|
||||||
|
'nilai' => 'required|integer|unique:crips,nilai,' . $id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cari data crips berdasarkan ID
|
||||||
|
$crip = Crip::find($id);
|
||||||
|
|
||||||
|
if (!$crip) {
|
||||||
|
toastr()->error('Data crips tidak ditemukan.');
|
||||||
|
return redirect()->route('crips');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ambil data dari request
|
||||||
|
$crip->nama = $request->input('nama');
|
||||||
|
$crip->nilai = $request->input('nilai');
|
||||||
|
|
||||||
|
// Cek apakah ada crips dengan nama atau nilai yang duplikat
|
||||||
|
$duplikat = Crip::where('nama', $crip->nama)
|
||||||
|
->orWhere('nilai', $crip->nilai)
|
||||||
|
->where('id', '!=', $id) // Pastikan tidak memeriksa data yang sedang diperbarui
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikat) {
|
||||||
|
toastr()->error('Nama atau nilai tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan perubahan
|
||||||
|
if ($crip->save()) {
|
||||||
|
toastr()->success('Data crips berhasil diperbarui.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data crips.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect ke halaman daftar crips
|
||||||
|
return redirect()->route('crips')->with('reload', true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function hapuscrips($id)
|
||||||
|
{
|
||||||
|
$crip = Crip::findOrFail($id);
|
||||||
|
$crip->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data crips berhasil dihapus.');
|
||||||
|
return redirect()->route('crips');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadcrips()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$crips = Crip::all();
|
||||||
|
$pdf = Pdf::loadView('admin.cripspdf', compact('crips'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_crips.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,401 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\SesiKuis;
|
||||||
|
use App\Models\JawabanKuis;
|
||||||
|
use App\Models\HasilSaw;
|
||||||
|
use App\Models\DetailSaw;
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
use App\Models\Kriteria;
|
||||||
|
use App\Models\Subkriteria;
|
||||||
|
use App\Models\OpsiSubkriteria;
|
||||||
|
use App\Models\Alternatif;
|
||||||
|
use App\Models\Crip;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Models\SystemSetting;
|
||||||
|
|
||||||
|
class DashboardController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
$siswa = Siswa::where('user_id', $user->id)->first();
|
||||||
|
$kurikulums = Kurikulum::all();
|
||||||
|
|
||||||
|
// Ambil kriterias untuk kurikulum pertama secara default
|
||||||
|
// Ini akan diganti saat user memilih kurikulum
|
||||||
|
$kriterias = Kriteria::with('subkriterias.opsisubkriterias')
|
||||||
|
->where('kurikulum_id', $kurikulums->first()->id ?? null)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Ambil riwayat perhitungan user
|
||||||
|
$sesikuisquery = SesiKuis::with(['kurikulum', 'hasilsaw.alternatif'])
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
|
$hasilitems = HasilSaw::with(['alternatif.mapels', 'alternatif.kurikulum'])
|
||||||
|
->where('sesi_kuis_id', $request->sesi_id)
|
||||||
|
->orderBy('peringkat')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Filter riwayat jika ada
|
||||||
|
if ($request->filled('kurikulum_id')) {
|
||||||
|
$sesikuisquery->where('kurikulum_id', $request->kurikulum_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('tanggal')) {
|
||||||
|
$sesikuisquery->whereDate('created_at', $request->tanggal);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sesikuis = $sesikuisquery->get();
|
||||||
|
|
||||||
|
// Cek apakah user pernah melakukan perhitungan sebelumnya
|
||||||
|
$showHistory = $sesikuis->isNotEmpty();
|
||||||
|
|
||||||
|
// Default: tidak ada hasil yang ditampilkan
|
||||||
|
$hasilsaw = null;
|
||||||
|
$hasilitems = collect();
|
||||||
|
|
||||||
|
// Jika ada parameter sesi_id, tampilkan hasil perhitungan spesifik
|
||||||
|
if ($request->has('sesi_id')) {
|
||||||
|
$hasilsaw = SesiKuis::with('kurikulum')->findOrFail($request->sesi_id);
|
||||||
|
$hasilitems = HasilSaw::with('alternatif')
|
||||||
|
->where('sesi_kuis_id', $request->sesi_id)
|
||||||
|
->orderBy('peringkat')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek apakah perhitungan dibuka oleh admin
|
||||||
|
$quizAccessStatus = SystemSetting::isPerhitunganOpen();
|
||||||
|
|
||||||
|
return view('dashboard', compact(
|
||||||
|
'siswa',
|
||||||
|
'kurikulums',
|
||||||
|
'kriterias',
|
||||||
|
'sesikuis',
|
||||||
|
'hasilsaw',
|
||||||
|
'hasilitems',
|
||||||
|
'showHistory',
|
||||||
|
'quizAccessStatus'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mendapatkan kriteria berdasarkan kurikulum
|
||||||
|
*/
|
||||||
|
public function getKriteriaByKurikulum(Request $request)
|
||||||
|
{
|
||||||
|
$kriterias = Kriteria::with('subkriterias.opsisubkriterias')
|
||||||
|
->where('kurikulum_id', $request->kurikulum_id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json($kriterias);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menampilkan hasil spesifik
|
||||||
|
*/
|
||||||
|
public function lihatHasil($sesiId)
|
||||||
|
{
|
||||||
|
// Validasi kepemilikan data
|
||||||
|
$user = Auth::user();
|
||||||
|
$sesikuis = SesiKuis::where('id', $sesiId)
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
// Redirect ke dashboard dengan parameter sesi_id
|
||||||
|
return redirect()->route('dashboard', ['sesi_id' => $sesiId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menghapus riwayat perhitungan
|
||||||
|
*/
|
||||||
|
public function hapusRiwayat($sesiId)
|
||||||
|
{
|
||||||
|
// Validasi kepemilikan data
|
||||||
|
$user = Auth::user();
|
||||||
|
$sesikuis = SesiKuis::where('id', $sesiId)
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
// Hapus data terkait
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Hapus hasil SAW
|
||||||
|
HasilSaw::where('sesi_kuis_id', $sesiId)->delete();
|
||||||
|
|
||||||
|
// Hapus jawaban
|
||||||
|
JawabanKuis::where('sesi_kuis_id', $sesiId)->delete();
|
||||||
|
|
||||||
|
// Hapus sesi kuis
|
||||||
|
$sesikuis->delete();
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return redirect()->route('dashboard', ['#riwayat'])->with('success', 'Riwayat berhasil dihapus!');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
return redirect()->back()->with('error', 'Gagal menghapus data: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function submitpenilaian(Request $request)
|
||||||
|
{
|
||||||
|
// 1. Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'sekolah' => 'required|string|max:255',
|
||||||
|
'kelas' => 'required|string|max:50',
|
||||||
|
'jawaban' => 'required|array'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
// 2. Buat sesi kuis baru
|
||||||
|
$sesikuis = SesiKuis::create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'kurikulum_id' => $request->kurikulum_id,
|
||||||
|
'nama' => $request->nama,
|
||||||
|
'sekolah' => $request->sekolah,
|
||||||
|
'kelas' => $request->kelas,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 3. Simpan semua jawaban pengguna
|
||||||
|
foreach ($request->jawaban as $subkriteria_id => $opsi_dipilih) {
|
||||||
|
JawabanKuis::create([
|
||||||
|
'sesi_kuis_id' => $sesikuis->id,
|
||||||
|
'subkriteria_id' => $subkriteria_id,
|
||||||
|
'opsi_dipilih' => $opsi_dipilih
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. HITUNG SAW - Bagian ini yang melakukan perhitungan
|
||||||
|
$this->hitungSAW($sesikuis);
|
||||||
|
|
||||||
|
// 5. Mark session as completed
|
||||||
|
$sesikuis->selesai_pada = now();
|
||||||
|
$sesikuis->save();
|
||||||
|
|
||||||
|
// Cek jika request adalah AJAX
|
||||||
|
if ($request->ajax() || $request->wantsJson()) {
|
||||||
|
// Load relasi yang diperlukan untuk response JSON
|
||||||
|
$sesikuis->load([
|
||||||
|
'kurikulum',
|
||||||
|
'hasilsaw.alternatif',
|
||||||
|
'hasilsaw' => function($query) {
|
||||||
|
$query->orderBy('peringkat');
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'hasil' => [
|
||||||
|
'nama' => $sesikuis->nama,
|
||||||
|
'sekolah' => $sesikuis->sekolah,
|
||||||
|
'kelas' => $sesikuis->kelas,
|
||||||
|
'kurikulum_nama' => $sesikuis->kurikulum->nama,
|
||||||
|
'tanggal' => $sesikuis->created_at->format('d F Y, H:i'),
|
||||||
|
'top3' => $sesikuis->hasilsaw->take(3)->map(function($item) {
|
||||||
|
return [
|
||||||
|
'peringkat' => $item->peringkat,
|
||||||
|
'nama' => $item->alternatif->nama,
|
||||||
|
'skor' => $item->skor_normalisasi,
|
||||||
|
'deskripsi' => $item->alternatif->deskripsi ?? 'Tidak ada deskripsi',
|
||||||
|
'total_skor' => $item->total_skor
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
'all' => $sesikuis->hasilsaw->map(function($item) {
|
||||||
|
return [
|
||||||
|
'peringkat' => $item->peringkat,
|
||||||
|
'nama' => $item->alternatif->nama,
|
||||||
|
'total_skor' => $item->total_skor,
|
||||||
|
'skor' => $item->skor_normalisasi
|
||||||
|
];
|
||||||
|
})
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('dashboard')
|
||||||
|
->with('success', 'Penilaian berhasil diselesaikan!')
|
||||||
|
->with('hasil_id', $sesikuis->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hitungSAW(SesiKuis $sesikuis)
|
||||||
|
{
|
||||||
|
// Ambil data yang diperlukan
|
||||||
|
$alternatifs = Alternatif::where('kurikulum_id', $sesikuis->kurikulum_id)->get();
|
||||||
|
$jawabankuis = $sesikuis->jawabankuis->keyBy('subkriteria_id');
|
||||||
|
|
||||||
|
// Array untuk menyimpan nilai awal dan nilai max/min
|
||||||
|
$nilaiAwal = [];
|
||||||
|
$maxNilaiKriteria = [];
|
||||||
|
$minNilaiKriteria = [];
|
||||||
|
|
||||||
|
// LANGKAH 1: Hitung nilai rata-rata per kriteria untuk setiap alternatif
|
||||||
|
foreach ($alternatifs as $alternatif) {
|
||||||
|
$nilaiAwal[$alternatif->id] = [];
|
||||||
|
|
||||||
|
foreach ($sesikuis->kurikulum->kriterias as $kriteria) {
|
||||||
|
$total_nilai_subkriteria = 0;
|
||||||
|
$jumlah_subkriteria_dijawab = 0;
|
||||||
|
|
||||||
|
// Hitung nilai untuk setiap subkriteria (soal) dalam kriteria ini
|
||||||
|
foreach ($kriteria->subkriterias as $subkriteria) {
|
||||||
|
if (isset($jawabankuis[$subkriteria->id])) {
|
||||||
|
$opsi_dipilih = $jawabankuis[$subkriteria->id]->opsi_dipilih;
|
||||||
|
|
||||||
|
$opsisubkriteria = OpsiSubkriteria::where('subkriteria_id', $subkriteria->id)
|
||||||
|
->where('alternatif_id', $alternatif->id)
|
||||||
|
->where('opsi', $opsi_dipilih)
|
||||||
|
->with('crips')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($opsisubkriteria && $opsisubkriteria->crips) {
|
||||||
|
$nilai_subkriteria = $opsisubkriteria->crips->nilai;
|
||||||
|
$total_nilai_subkriteria += $nilai_subkriteria;
|
||||||
|
$jumlah_subkriteria_dijawab++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hitung rata-rata per kriteria
|
||||||
|
$nilai_kriteria = ($jumlah_subkriteria_dijawab > 0) ?
|
||||||
|
($total_nilai_subkriteria / $jumlah_subkriteria_dijawab) : 0;
|
||||||
|
|
||||||
|
// Simpan nilai kriteria untuk alternatif ini
|
||||||
|
$nilaiAwal[$alternatif->id][$kriteria->id] = $nilai_kriteria;
|
||||||
|
|
||||||
|
// Update nilai max dan min untuk kriteria ini
|
||||||
|
if (!isset($maxNilaiKriteria[$kriteria->id]) || $nilai_kriteria > $maxNilaiKriteria[$kriteria->id]) {
|
||||||
|
$maxNilaiKriteria[$kriteria->id] = $nilai_kriteria;
|
||||||
|
}
|
||||||
|
if (!isset($minNilaiKriteria[$kriteria->id]) || $nilai_kriteria < $minNilaiKriteria[$kriteria->id]) {
|
||||||
|
$minNilaiKriteria[$kriteria->id] = $nilai_kriteria;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LANGKAH 2: Normalisasi dan hitung skor total
|
||||||
|
$skorAlternatif = [];
|
||||||
|
|
||||||
|
foreach ($alternatifs as $alternatif) {
|
||||||
|
$skorAlternatif[$alternatif->id] = [
|
||||||
|
'total_skor' => 0,
|
||||||
|
'kriteria_normalisasi' => [],
|
||||||
|
'kriteria_skor' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($sesikuis->kurikulum->kriterias as $kriteria) {
|
||||||
|
$nilai = $nilaiAwal[$alternatif->id][$kriteria->id];
|
||||||
|
$max = $maxNilaiKriteria[$kriteria->id];
|
||||||
|
$min = $minNilaiKriteria[$kriteria->id];
|
||||||
|
|
||||||
|
// Normalisasi berdasarkan tipe kriteria
|
||||||
|
$jenis_kriteria = strtolower($kriteria->tipe ?? 'benefit');
|
||||||
|
|
||||||
|
if ($max == $min) {
|
||||||
|
// Jika semua nilai sama, berikan nilai normalisasi 1.0
|
||||||
|
$nilai_normalisasi = 1.0;
|
||||||
|
} else {
|
||||||
|
if ($jenis_kriteria === 'benefit') {
|
||||||
|
// Untuk kriteria benefit: Rij = Xij / Max{Xij}
|
||||||
|
$nilai_normalisasi = ($max > 0) ? ($nilai / $max) : 0;
|
||||||
|
} else {
|
||||||
|
// Untuk kriteria cost: Rij = Min{Xij} / Xij
|
||||||
|
$nilai_normalisasi = ($nilai > 0) ? ($min / $nilai) : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kalikan dengan bobot kriteria
|
||||||
|
$bobot = floatval($kriteria->bobot);
|
||||||
|
$skor_dengan_bobot = $nilai_normalisasi * $bobot;
|
||||||
|
|
||||||
|
// Simpan nilai normalisasi dan skor mentah
|
||||||
|
$skorAlternatif[$alternatif->id]['kriteria_normalisasi'][$kriteria->id] = $nilai_normalisasi;
|
||||||
|
$skorAlternatif[$alternatif->id]['kriteria_skor'][$kriteria->id] = $nilai;
|
||||||
|
|
||||||
|
// Tambahkan ke skor total
|
||||||
|
$skorAlternatif[$alternatif->id]['total_skor'] += $skor_dengan_bobot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round total skor di akhir
|
||||||
|
$skorAlternatif[$alternatif->id]['total_skor'] = round($skorAlternatif[$alternatif->id]['total_skor'], 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// LANGKAH 3: Urutkan berdasarkan skor (ranking)
|
||||||
|
uasort($skorAlternatif, function($a, $b) {
|
||||||
|
return $b['total_skor'] <=> $a['total_skor'];
|
||||||
|
});
|
||||||
|
|
||||||
|
// LANGKAH 4: Simpan hasil ke database
|
||||||
|
$ranking = 1;
|
||||||
|
foreach ($skorAlternatif as $alternatif_id => $skorData) {
|
||||||
|
$hasilsaw = HasilSaw::create([
|
||||||
|
'sesi_kuis_id' => $sesikuis->id,
|
||||||
|
'alternatif_id' => $alternatif_id,
|
||||||
|
'total_skor' => $skorData['total_skor'],
|
||||||
|
'skor_normalisasi' => $skorData['total_skor'],
|
||||||
|
'peringkat' => $ranking++
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Simpan detail SAW
|
||||||
|
$this->simpanDetailSAW($hasilsaw, $sesikuis, $skorData['kriteria_skor'], $skorData['kriteria_normalisasi']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function simpanDetailSAW(HasilSaw $hasilsaw, SesiKuis $sesikuis, array $kriteria_skor, array $kriteria_normalisasi)
|
||||||
|
{
|
||||||
|
$jawabankuis = $sesikuis->jawabankuis->keyBy('subkriteria_id');
|
||||||
|
|
||||||
|
foreach ($kriteria_skor as $kriteria_id => $skor_rata_rata) {
|
||||||
|
$kriteria = Kriteria::find($kriteria_id);
|
||||||
|
$nilai_normalisasi_kriteria = $kriteria_normalisasi[$kriteria_id];
|
||||||
|
$skor_akhir_kriteria = $nilai_normalisasi_kriteria * $kriteria->bobot;
|
||||||
|
|
||||||
|
// Cari subkriteria pertama yang dijawab sebagai representasi
|
||||||
|
$subkriteria_representatif = null;
|
||||||
|
$opsi_subkriteria_representatif = null;
|
||||||
|
|
||||||
|
foreach ($kriteria->subkriterias as $subkriteria) {
|
||||||
|
if (isset($jawabankuis[$subkriteria->id])) {
|
||||||
|
$opsi_dipilih = $jawabankuis[$subkriteria->id]->opsi_dipilih;
|
||||||
|
|
||||||
|
$opsisubkriteria = OpsiSubkriteria::where('subkriteria_id', $subkriteria->id)
|
||||||
|
->where('alternatif_id', $hasilsaw->alternatif_id)
|
||||||
|
->where('opsi', $opsi_dipilih)
|
||||||
|
->with('crips')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($opsisubkriteria && $opsisubkriteria->crips) {
|
||||||
|
$subkriteria_representatif = $subkriteria->id;
|
||||||
|
$opsi_subkriteria_representatif = $opsisubkriteria->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan jika ada subkriteria representatif
|
||||||
|
if ($subkriteria_representatif) {
|
||||||
|
DetailSaw::create([
|
||||||
|
'hasil_saw_id' => $hasilsaw->id,
|
||||||
|
'kriteria_id' => $kriteria_id,
|
||||||
|
'subkriteria_id' => $subkriteria_representatif,
|
||||||
|
'opsi_subkriteria_id' => $opsi_subkriteria_representatif,
|
||||||
|
'nilai_normalisasi' => $nilai_normalisasi_kriteria,
|
||||||
|
'nilai_bobot' => $kriteria->bobot,
|
||||||
|
'skor_akhir' => round($skor_akhir_kriteria, 6)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
use App\Models\Sekolah;
|
||||||
|
use App\Models\SesiKuis;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use App\Models\SystemSetting;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
|
||||||
|
class HomeController extends Controller
|
||||||
|
{
|
||||||
|
public function dashboard()
|
||||||
|
{
|
||||||
|
$admin = Auth::user();
|
||||||
|
|
||||||
|
// Ambil total siswa
|
||||||
|
$totalSiswa = Siswa::count();
|
||||||
|
$totalKurikulum = Kurikulum::count();
|
||||||
|
$totalResponden = SesiKuis::count();
|
||||||
|
$totalSekolah = Sekolah::count();
|
||||||
|
|
||||||
|
// Tambah status quiz access
|
||||||
|
$quizAccessStatus = SystemSetting::isPerhitunganOpen();
|
||||||
|
|
||||||
|
return view('admin.dashboard', compact('admin', 'totalSiswa', 'totalKurikulum', 'totalResponden', 'totalSekolah', 'quizAccessStatus'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tambah method untuk toggle quiz access
|
||||||
|
public function toggleQuizAccess()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$newStatus = SystemSetting::togglePerhitunganOpen();
|
||||||
|
|
||||||
|
if ($newStatus) {
|
||||||
|
toastr()->success('Akses quiz berhasil dibuka untuk semua user');
|
||||||
|
} else {
|
||||||
|
toastr()->success('Akses quiz berhasil ditutup');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'status' => $newStatus,
|
||||||
|
'message' => $newStatus
|
||||||
|
? 'Akses quiz berhasil dibuka untuk semua user'
|
||||||
|
: 'Akses quiz berhasil ditutup'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
toastr()->error('Terjadi kesalahan: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Terjadi kesalahan: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Kriteria;
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class KriteriaController extends Controller
|
||||||
|
{
|
||||||
|
public function kriteria()
|
||||||
|
{
|
||||||
|
$kriterias = Kriteria::with('kurikulum')->get();
|
||||||
|
$kurikulums = Kurikulum::all();
|
||||||
|
return view('admin.kriteria', compact('kriterias', 'kurikulums'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function tambahkriteria(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'jenis' => 'required|in:Benefit,Cost',
|
||||||
|
'bobot' => [
|
||||||
|
'required',
|
||||||
|
'numeric',
|
||||||
|
'min:0',
|
||||||
|
'max:1',
|
||||||
|
'regex:/^(0(\.\d{1,2})?|1(\.0{1,2})?)$/',
|
||||||
|
],
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
], [
|
||||||
|
'bobot.numeric' => 'Bobot harus berupa angka desimal, misalnya 0.50.',
|
||||||
|
'bobot.min' => 'Bobot minimal adalah 0.',
|
||||||
|
'bobot.max' => 'Bobot maksimal adalah 1.00.',
|
||||||
|
'bobot.regex' => 'Format bobot harus dua angka di belakang koma, contoh: 0.20 atau 1.00.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cek apakah nama kriteria sudah ada dalam kurikulum yang sama
|
||||||
|
$duplikatNama = Kriteria::where('nama', $request->nama)
|
||||||
|
->where('kurikulum_id', $request->kurikulum_id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Nama kriteria sudah ada dalam kurikulum yang sama.');
|
||||||
|
return redirect()->back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cek total bobot agar tidak melebihi 1
|
||||||
|
$totalBobot = Kriteria::where('kurikulum_id', $request->kurikulum_id)->sum('bobot');
|
||||||
|
$bobotBaru = $request->bobot;
|
||||||
|
|
||||||
|
if (($totalBobot + $bobotBaru) > 1) {
|
||||||
|
toastr()->error('Total bobot untuk kurikulum ini melebihi 1.0. Silakan periksa kembali.');
|
||||||
|
return redirect()->back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan data kriteria
|
||||||
|
$kriteria = new Kriteria();
|
||||||
|
$kriteria->nama = $request->nama;
|
||||||
|
$kriteria->jenis = $request->jenis;
|
||||||
|
$kriteria->bobot = $bobotBaru;
|
||||||
|
$kriteria->kurikulum_id = $request->kurikulum_id;
|
||||||
|
|
||||||
|
if ($kriteria->save()) {
|
||||||
|
toastr()->success('Kriteria berhasil ditambahkan');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan kriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('kriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function updatekriteria(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'jenis' => 'required|in:Benefit,Cost',
|
||||||
|
'bobot' => [
|
||||||
|
'required',
|
||||||
|
'numeric',
|
||||||
|
'min:0',
|
||||||
|
'max:1',
|
||||||
|
'regex:/^(0(\.\d{1,2})?|1(\.0{1,2})?)$/',
|
||||||
|
],
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
], [
|
||||||
|
'bobot.numeric' => 'Bobot harus berupa angka desimal, misalnya 0.50.',
|
||||||
|
'bobot.min' => 'Bobot minimal adalah 0.',
|
||||||
|
'bobot.max' => 'Bobot maksimal adalah 1.00.',
|
||||||
|
'bobot.regex' => 'Format bobot harus dua angka di belakang koma, contoh: 0.20 atau 1.00.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$kriteria = Kriteria::findOrFail($id);
|
||||||
|
|
||||||
|
// Cek duplikat nama (kecuali untuk dirinya sendiri)
|
||||||
|
$duplikatNama = Kriteria::where('nama', $request->nama)
|
||||||
|
->where('kurikulum_id', $request->kurikulum_id)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Nama kriteria sudah ada dalam kurikulum yang sama.');
|
||||||
|
return redirect()->back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cek total bobot: kurangi dulu bobot lama, lalu tambah bobot baru
|
||||||
|
$totalBobot = Kriteria::where('kurikulum_id', $request->kurikulum_id)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->sum('bobot');
|
||||||
|
$bobotBaru = $request->bobot;
|
||||||
|
|
||||||
|
if (($totalBobot + $bobotBaru) > 1) {
|
||||||
|
toastr()->error('Total bobot untuk kurikulum ini melebihi 1.0. Silakan periksa kembali.');
|
||||||
|
return redirect()->back()->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update data
|
||||||
|
$kriteria->nama = $request->nama;
|
||||||
|
$kriteria->jenis = $request->jenis;
|
||||||
|
$kriteria->bobot = $bobotBaru;
|
||||||
|
$kriteria->kurikulum_id = $request->kurikulum_id;
|
||||||
|
|
||||||
|
if ($kriteria->save()) {
|
||||||
|
toastr()->success('Kriteria berhasil diperbarui');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui kriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('kriteria')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapuskriteria($id)
|
||||||
|
{
|
||||||
|
$kriteria = Kriteria::findOrFail($id);
|
||||||
|
if ($kriteria->delete()) {
|
||||||
|
toastr()->success('Kriteria berhasil dihapus');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menghapus kriteria');
|
||||||
|
}
|
||||||
|
return redirect()->route('kriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadkriteria()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$kriterias = Kriteria::all();
|
||||||
|
$pdf = Pdf::loadView('admin.kriteriapdf', compact('kriterias'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_kriterias.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class KurikulumController extends Controller
|
||||||
|
{
|
||||||
|
public function kurikulum()
|
||||||
|
{
|
||||||
|
$kurikulums = Kurikulum::all();
|
||||||
|
return view('admin.kurikulum', compact('kurikulums'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahkurikulum(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
|
||||||
|
// Cek apakah ada nama yang duplikat
|
||||||
|
$duplikatNama = Kurikulum::where('nama', $nama)->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Kurikulum dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$kurikulum = new Kurikulum();
|
||||||
|
$kurikulum->nama = $nama;
|
||||||
|
|
||||||
|
if ($kurikulum->save()) {
|
||||||
|
toastr()->success('Data kurikulum berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data kurikulum.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('kurikulum');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatekurikulum(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$kurikulum = Kurikulum::findOrFail($id);
|
||||||
|
|
||||||
|
// Ambil nilai dari request
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
|
||||||
|
// Cek apakah ada nama yang duplikat
|
||||||
|
$duplikatNama = Kurikulum::where('nama', $nama)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Kurikulum dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$kurikulum->nama = $nama;
|
||||||
|
|
||||||
|
if ($kurikulum->save()) {
|
||||||
|
toastr()->success('Data kurikulum berhasil diperbarui.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data kurikulum.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('kurikulum')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapuskurikulum($id)
|
||||||
|
{
|
||||||
|
$kurikulum = Kurikulum::findOrFail($id);
|
||||||
|
$kurikulum->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data kurikulum berhasil dihapus.');
|
||||||
|
return redirect()->route('kurikulum');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadkurikulum()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$kurikulums = Kurikulum::all();
|
||||||
|
$pdf = Pdf::loadView('admin.kurikulumpdf', compact('kurikulums'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_kurikulum.pdf');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
use App\Models\Mapel;
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class MapelController extends Controller
|
||||||
|
{
|
||||||
|
public function mapel()
|
||||||
|
{
|
||||||
|
$mapels = Mapel::with('kurikulum')->get();
|
||||||
|
$kurikulums = Kurikulum::all();
|
||||||
|
return view('admin.mapel', compact('mapels', 'kurikulums'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function tambahmapel(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'kategori' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
|
||||||
|
// Cek apakah ada mapel dengan nama yang duplikat, tanpa memperhatikan kategori dan kurikulum
|
||||||
|
$duplikatNama = Mapel::where('nama', $nama)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Mapel dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$mapel = new Mapel();
|
||||||
|
$mapel->kurikulum_id = $request->kurikulum_id;
|
||||||
|
$mapel->nama = $nama;
|
||||||
|
$mapel->kategori = $request->kategori;
|
||||||
|
|
||||||
|
if ($mapel->save()) {
|
||||||
|
toastr()->success('Data mata pelajaran berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data mata pelajaran.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('mapel');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function updatemapel(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'kurikulum_id' => 'required|exists:kurikulums,id',
|
||||||
|
'nama' => 'required|string',
|
||||||
|
'kategori' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$mapel = Mapel::findOrFail($id);
|
||||||
|
|
||||||
|
// Ambil nilai dari request
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
|
||||||
|
// Cek apakah ada mapel dengan nama yang duplikat, tanpa memperhatikan kategori dan kurikulum
|
||||||
|
$duplikatNama = Mapel::where('nama', $nama)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Mata pelajaran dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$mapel->kurikulum_id = $request->kurikulum_id;
|
||||||
|
$mapel->nama = $nama;
|
||||||
|
$mapel->kategori = $request->kategori;
|
||||||
|
|
||||||
|
if ($mapel->save()) {
|
||||||
|
toastr()->success('Data mata pelajaran berhasil diperbarui.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data mata pelajaran.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('mapel')->with('reload', true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapusmapel($id)
|
||||||
|
{
|
||||||
|
$mapel = Mapel::findOrFail($id);
|
||||||
|
$mapel->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data mata pelajaran berhasil dihapus.');
|
||||||
|
return redirect()->route('mapel');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadmapel()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$mapels = Mapel::all();
|
||||||
|
$pdf = Pdf::loadView('admin.mapelpdf', compact('mapels'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_mapels.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\OpsiSubkriteria;
|
||||||
|
use App\Models\Alternatif; // Pastikan model Alternatif digunakan
|
||||||
|
use App\Models\Subkriteria;
|
||||||
|
use App\Models\Crip;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class OpsiSubkriteriaController extends Controller
|
||||||
|
{
|
||||||
|
public function opsisubkriteria()
|
||||||
|
{
|
||||||
|
// Mengambil data opsi subkriteria, dengan relasi ke subkriteria, crips, dan alternatif
|
||||||
|
$opsisubkriterias = OpsiSubkriteria::with(['subkriteria', 'crips', 'alternatif'])->get();
|
||||||
|
|
||||||
|
// Mengambil semua data crips dan alternatif
|
||||||
|
$crips = Crip::all();
|
||||||
|
$alternatifs = Alternatif::all();
|
||||||
|
$subkriterias = Subkriteria::all();
|
||||||
|
|
||||||
|
return view('admin.opsisubkriteria', compact('opsisubkriterias', 'crips', 'alternatifs', 'subkriterias'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahopsisubkriteria(Request $request)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'subkriteria_id' => 'required|exists:subkriterias,id',
|
||||||
|
'alternatif_id' => 'required|exists:alternatifs,id',
|
||||||
|
'crips_id' => 'required|exists:crips,id',
|
||||||
|
'opsi' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cek duplikat opsi untuk kombinasi subkriteria + alternatif
|
||||||
|
$duplikat = OpsiSubkriteria::where('subkriteria_id', $request->subkriteria_id)
|
||||||
|
->where('alternatif_id', $request->alternatif_id)
|
||||||
|
->where('opsi', $request->opsi)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikat) {
|
||||||
|
toastr()->error('Opsi tersebut sudah ada untuk kombinasi subkriteria dan alternatif ini.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan data opsi subkriteria
|
||||||
|
$opsi = new OpsiSubkriteria();
|
||||||
|
$opsi->subkriteria_id = $request->subkriteria_id;
|
||||||
|
$opsi->alternatif_id = $request->alternatif_id;
|
||||||
|
$opsi->crips_id = $request->crips_id;
|
||||||
|
$opsi->opsi = $request->opsi;
|
||||||
|
|
||||||
|
if ($opsi->save()) {
|
||||||
|
toastr()->success('Opsi subkriteria berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan opsi subkriteria.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('opsisubkriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateopsisubkriteria(Request $request, $id)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'subkriteria_id' => 'required|exists:subkriterias,id',
|
||||||
|
'alternatif_id' => 'required|exists:alternatifs,id',
|
||||||
|
'crips_id' => 'required|exists:crips,id',
|
||||||
|
'opsi' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil data berdasarkan ID
|
||||||
|
$opsi = OpsiSubkriteria::findOrFail($id);
|
||||||
|
|
||||||
|
// Cek duplikat (kecuali jika data yang sama persis dengan yang sedang diedit)
|
||||||
|
$duplikat = OpsiSubkriteria::where('subkriteria_id', $request->subkriteria_id)
|
||||||
|
->where('alternatif_id', $request->alternatif_id)
|
||||||
|
->where('opsi', $request->opsi)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikat) {
|
||||||
|
toastr()->error('Opsi tersebut sudah ada untuk kombinasi subkriteria dan alternatif ini.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update data
|
||||||
|
$opsi->subkriteria_id = $request->subkriteria_id;
|
||||||
|
$opsi->alternatif_id = $request->alternatif_id;
|
||||||
|
$opsi->crips_id = $request->crips_id;
|
||||||
|
$opsi->opsi = $request->opsi;
|
||||||
|
|
||||||
|
if ($opsi->save()) {
|
||||||
|
toastr()->success('Opsi subkriteria berhasil diperbarui.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui opsi subkriteria.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('opsisubkriteria')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapusopsisubkriteria($id)
|
||||||
|
{
|
||||||
|
// Cari data opsi subkriteria berdasarkan ID
|
||||||
|
$opsisubkriteria = OpsiSubkriteria::findOrFail($id);
|
||||||
|
|
||||||
|
// Hapus data opsi subkriteria
|
||||||
|
$opsisubkriteria->delete();
|
||||||
|
|
||||||
|
// Tampilkan pesan sukses
|
||||||
|
toastr()->success('Data opsi subkriteria berhasil dihapus.');
|
||||||
|
|
||||||
|
// Redirect kembali ke halaman opsi subkriteria
|
||||||
|
return redirect()->route('opsisubkriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadopsisubkriteria()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$opsisubkriterias = OpsiSubkriteria::all();
|
||||||
|
$subkriterias = Subkriteria::all();
|
||||||
|
$pdf = Pdf::loadView('admin.opsubpdf', compact('opsisubkriterias', 'subkriterias'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_opsisubkriterias.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\SesiKuis;
|
||||||
|
use App\Models\HasilSaw;
|
||||||
|
use App\Models\JawabanKuis;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
use App\Models\Kriteria;
|
||||||
|
use App\Models\Alternatif;
|
||||||
|
use App\Models\Subkriteria;
|
||||||
|
use App\Models\DetailHasilSaw;
|
||||||
|
|
||||||
|
class PerhitunganController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the SAW calculation results.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$hasilsaw = HasilSaw::with(['sesikuis', 'alternatif.mapels'])->orderBy('sesi_kuis_id')->orderBy('peringkat')->get();
|
||||||
|
$sesikuis = SesiKuis::with('user', 'kurikulum')->orderBy('created_at', 'desc')->get();
|
||||||
|
$jawaban = JawabanKuis::with(['sesikuis', 'subkriteria'])->orderBy('sesi_kuis_id')->get();
|
||||||
|
|
||||||
|
return view('admin.perhitungan', compact('hasilsaw', 'sesikuis', 'jawaban'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get detail of session quiz.
|
||||||
|
*/
|
||||||
|
public function getSesiDetail($id)
|
||||||
|
{
|
||||||
|
$sesi = SesiKuis::with('kurikulum', 'user')->findOrFail($id);
|
||||||
|
|
||||||
|
// Get SAW results for this session
|
||||||
|
$hasil = HasilSaw::with('alternatif.mapels')
|
||||||
|
->where('sesi_kuis_id', $id)
|
||||||
|
->orderBy('peringkat', 'asc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Get answers for this session
|
||||||
|
$jawaban = JawabanKuis::with('subkriteria')
|
||||||
|
->where('sesi_kuis_id', $id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'sesi' => $sesi,
|
||||||
|
'hasil' => $hasil,
|
||||||
|
'jawaban' => $jawaban
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add these methods to your SawController or relevant controller
|
||||||
|
public function printSesiPDF($id)
|
||||||
|
{
|
||||||
|
// Get the session data
|
||||||
|
$sesi = SesiKuis::with(['kurikulum'])->findOrFail($id);
|
||||||
|
|
||||||
|
// Get the results for this session
|
||||||
|
$hasil = HasilSaw::with(['alternatif'])
|
||||||
|
->where('sesi_kuis_id', $id)
|
||||||
|
->orderBy('peringkat', 'asc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Get the answers for this session
|
||||||
|
$jawaban = JawabanKuis::with(['subkriteria'])
|
||||||
|
->where('sesi_kuis_id', $id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Generate PDF
|
||||||
|
$pdf = PDF::loadView('admin.sesi_detail_pdf', compact('sesi', 'hasil', 'jawaban'));
|
||||||
|
|
||||||
|
// Download the PDF
|
||||||
|
return $pdf->download('hasil_sesi_' . $sesi->nama . '.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function printAllSesiPDF()
|
||||||
|
{
|
||||||
|
// Get all session data
|
||||||
|
$allSesi = SesiKuis::with(['kurikulum'])->orderBy('created_at', 'desc')->get();
|
||||||
|
|
||||||
|
// Collect all results and answers for each session
|
||||||
|
$data = [];
|
||||||
|
foreach ($allSesi as $sesi) {
|
||||||
|
$hasil = HasilSaw::with(['alternatif'])
|
||||||
|
->where('sesi_kuis_id', $sesi->id)
|
||||||
|
->orderBy('peringkat', 'asc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$jawaban = JawabanKuis::with(['subkriteria'])
|
||||||
|
->where('sesi_kuis_id', $sesi->id)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$data[] = [
|
||||||
|
'sesi' => $sesi,
|
||||||
|
'hasil' => $hasil,
|
||||||
|
'jawaban' => $jawaban
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate PDF
|
||||||
|
$pdf = PDF::loadView('admin.all_sesi_pdf', compact('data'));
|
||||||
|
|
||||||
|
// Download the PDF
|
||||||
|
return $pdf->download('semua_hasil_sesi.pdf');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\ProfileUpdateRequest;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Redirect;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the user's profile form.
|
||||||
|
*/
|
||||||
|
public function edit(Request $request): View
|
||||||
|
{
|
||||||
|
return view('profile.edit', [
|
||||||
|
'user' => $request->user(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the user's profile information.
|
||||||
|
*/
|
||||||
|
public function update(ProfileUpdateRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->user()->fill($request->validated());
|
||||||
|
|
||||||
|
if ($request->user()->isDirty('email')) {
|
||||||
|
$request->user()->email_verified_at = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->user()->save();
|
||||||
|
|
||||||
|
return Redirect::route('profile.edit')->with('status', 'profile-updated');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the user's account.
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validateWithBag('userDeletion', [
|
||||||
|
'password' => ['required', 'current_password'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
$user->delete();
|
||||||
|
|
||||||
|
$request->session()->invalidate();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
return Redirect::to('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function profilesaya()
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
return view('admin.profilesaya', compact('user'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function updateprofilesaya(Request $request)
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
$validated = $request->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'email',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique('users')->ignore($user->id),
|
||||||
|
],
|
||||||
|
'password_current' => ['nullable', 'string'],
|
||||||
|
'password' => ['nullable', 'string', 'min:8'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Jika ada password baru, verifikasi password lama
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
if (!$request->filled('password_current')) {
|
||||||
|
return back()->with('error', 'Kata sandi saat ini diperlukan untuk mengubah kata sandi');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Hash::check($request->password_current, $user->password)) {
|
||||||
|
return back()->with('error', 'Kata sandi saat ini tidak cocok');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buat array data yang akan diupdate
|
||||||
|
$updateData = [
|
||||||
|
'name' => $validated['name'],
|
||||||
|
'email' => $validated['email'],
|
||||||
|
'usertype' => $user->usertype, // Pertahankan usertype (tanpa underscore)
|
||||||
|
];
|
||||||
|
|
||||||
|
// Tambahkan password jika ada
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
$updateData['password'] = Hash::make($validated['password']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update user
|
||||||
|
User::where('id', $user->id)->update($updateData);
|
||||||
|
|
||||||
|
// Logout user setelah update profil
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
// Invalidate session untuk keamanan
|
||||||
|
$request->session()->invalidate();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
// Redirect ke halaman login dengan pesan sukses
|
||||||
|
return redirect()->route('login')->with('success', 'Profil berhasil diperbarui. Silakan login kembali.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function deleteprofilesaya()
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
$userId = $user->id;
|
||||||
|
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
// Hapus user dari database
|
||||||
|
User::where('id', $userId)->delete();
|
||||||
|
|
||||||
|
return redirect()->route('login')->with('success', 'Akun Anda telah dihapus');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\Kurikulum;
|
||||||
|
|
||||||
|
class QuizController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,355 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Sekolah;
|
||||||
|
use App\Models\Kelas;
|
||||||
|
use App\Models\Siswa;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
|
||||||
|
class SekolahController extends Controller
|
||||||
|
{
|
||||||
|
public function sekolah()
|
||||||
|
{
|
||||||
|
$sekolahs = Sekolah::all();
|
||||||
|
return view('admin.sekolah', compact('sekolahs'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahsekolah(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required',
|
||||||
|
'alamat' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil nilai dari request
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
$alamat = $request->input('alamat');
|
||||||
|
|
||||||
|
// Cek apakah ada kombinasi nama dan alamat yang sudah ada
|
||||||
|
$duplikatNamaAlamat = Sekolah::where('nama', $nama)
|
||||||
|
->where('alamat', $alamat)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
// Cek apakah ada nama yang duplikat
|
||||||
|
$duplikatNama = Sekolah::where('nama', $nama)->exists();
|
||||||
|
|
||||||
|
// Cek apakah ada alamat yang duplikat
|
||||||
|
$duplikatAlamat = Sekolah::where('alamat', $alamat)->exists();
|
||||||
|
|
||||||
|
if ($duplikatNamaAlamat) {
|
||||||
|
toastr()->error('Sekolah dengan nama dan alamat tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Sekolah dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($duplikatAlamat) {
|
||||||
|
toastr()->error('Sekolah dengan alamat tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$sekolah = new Sekolah();
|
||||||
|
$sekolah->nama = $request->input('nama');
|
||||||
|
$sekolah->alamat = $request->input('alamat');
|
||||||
|
|
||||||
|
if ($sekolah->save()) {
|
||||||
|
toastr()->success('Data sekolah berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data sekolah.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('sekolah');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatesekolah(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required',
|
||||||
|
'alamat' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil data sekolah berdasarkan ID
|
||||||
|
$sekolah = Sekolah::findOrFail($id);
|
||||||
|
|
||||||
|
// Ambil nilai dari request
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
$alamat = $request->input('alamat');
|
||||||
|
|
||||||
|
|
||||||
|
// Cek apakah ada nama yang duplikat (karena nama unique di database)
|
||||||
|
$duplikatNama = Sekolah::where('nama', $nama)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Sekolah dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek apakah ada alamat yang duplikat
|
||||||
|
$duplikatAlamat = Sekolah::where('alamat', $alamat)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatAlamat) {
|
||||||
|
toastr()->error('Sekolah dengan alamat tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update data sekolah
|
||||||
|
$sekolah->nama = $nama;
|
||||||
|
$sekolah->alamat = $alamat;
|
||||||
|
$sekolah->save();
|
||||||
|
|
||||||
|
toastr()->success('Data sekolah berhasil diupdate.');
|
||||||
|
return redirect()->route('sekolah')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapussekolah($id)
|
||||||
|
{
|
||||||
|
$sekolah = Sekolah::findOrFail($id);
|
||||||
|
$sekolah->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data sekolah berhasil dihapus.');
|
||||||
|
return redirect()->route('sekolah');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadsekolah()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$sekolahs = Sekolah::all();
|
||||||
|
$pdf = Pdf::loadView('admin.sekolahpdf', compact('sekolahs'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_sekolah.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kelas()
|
||||||
|
{
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$sekolahs = Sekolah::all();
|
||||||
|
return view('admin.kelas', compact('kelas', 'sekolahs'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getkelas($id)
|
||||||
|
{
|
||||||
|
$kelas = Kelas::where('sekolah_id', $id)->get();
|
||||||
|
// Balikkan dalam bentuk JSON
|
||||||
|
return response()->json(['kelas' => $kelas]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function tambahkelas(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama_kelas' => 'required',
|
||||||
|
'sekolah_id' => 'required|exists:sekolahs,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil nilai dari request
|
||||||
|
$nama = $request->input('nama_kelas');
|
||||||
|
|
||||||
|
// Cek apakah ada nama yang duplikat
|
||||||
|
$duplikatNama = Kelas::where('nama_kelas', $nama)
|
||||||
|
->where('sekolah_id', $request->input('sekolah_id'))
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Kelas dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$kelas = new Kelas();
|
||||||
|
$kelas->nama_kelas = $request->input('nama_kelas');
|
||||||
|
$kelas->sekolah_id = $request->input('sekolah_id');
|
||||||
|
|
||||||
|
if ($kelas->save()) {
|
||||||
|
toastr()->success('Data kelas berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data kelas.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('kelas');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatekelas(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama_kelas' => 'required',
|
||||||
|
'sekolah_id' => 'required|exists:sekolahs,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil data kelas berdasarkan ID
|
||||||
|
$kelas = Kelas::findOrFail($id);
|
||||||
|
|
||||||
|
// Ambil nilai dari request
|
||||||
|
$nama = $request->input('nama_kelas');
|
||||||
|
|
||||||
|
// Cek apakah ada nama yang duplikat, kecuali untuk kelas yang sedang diupdate
|
||||||
|
$duplikatNama = Kelas::where('nama_kelas', $nama)
|
||||||
|
->where('sekolah_id', $request->input('sekolah_id'))
|
||||||
|
->where('id', '!=', $id) // Menghindari duplikasi pada kelas yang sedang diupdate
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Kelas dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update data kelas
|
||||||
|
$kelas->nama_kelas = $nama;
|
||||||
|
$kelas->sekolah_id = $request->input('sekolah_id');
|
||||||
|
|
||||||
|
if ($kelas->save()) {
|
||||||
|
toastr()->success('Data kelas berhasil diupdate.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data kelas.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('kelas')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapuskelas($id)
|
||||||
|
{
|
||||||
|
$kelas = Kelas::findOrFail($id);
|
||||||
|
$kelas->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data kelas berhasil dihapus.');
|
||||||
|
return redirect()->route('kelas');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadkelas()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$kelas = Kelas::all();
|
||||||
|
$pdf = Pdf::loadView('admin.kelaspdf', compact('kelas'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_kelas.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function siswa()
|
||||||
|
{
|
||||||
|
$users = User::where('usertype', 'user')->get();
|
||||||
|
$sekolahs = Sekolah::all(); // Untuk dropdown sekolah
|
||||||
|
$kelas = Kelas::all(); // Untuk dropdown kelas
|
||||||
|
$tahun_ajarans = TahunAjaran::where('is_active', 1)->get(); // Ambil tahun ajaran yang aktif
|
||||||
|
$siswas = Siswa::with('user', 'sekolah', 'kelas', 'tahunAjaran')->get(); // Tambahkan relasi 'tahunAjaran'
|
||||||
|
|
||||||
|
return view('admin.siswa', compact('siswas', 'users', 'sekolahs', 'kelas', 'tahun_ajarans'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahsiswa(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'user_id' => 'required|exists:users,id',
|
||||||
|
'sekolah_id' => 'required|exists:sekolahs,id',
|
||||||
|
'kelas_id' => 'required|exists:kelas,id',
|
||||||
|
'tahun_ajaran_id' => 'required|exists:tahun_ajarans,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$userId = $request->input('user_id');
|
||||||
|
$sekolahId = $request->input('sekolah_id');
|
||||||
|
$kelasId = $request->input('kelas_id');
|
||||||
|
$tahunAjaranId = $request->input('tahun_ajaran_id');
|
||||||
|
|
||||||
|
// Cek apakah siswa ini sudah terdaftar di sekolah, kelas, dan tahun ajaran yang sama
|
||||||
|
$duplikat = Siswa::where('user_id', $userId)
|
||||||
|
->where('sekolah_id', $sekolahId)
|
||||||
|
->where('kelas_id', $kelasId)
|
||||||
|
->where('tahun_ajaran_id', $tahunAjaranId)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikat) {
|
||||||
|
toastr()->error('Siswa tersebut sudah terdaftar di sekolah, kelas, dan tahun ajaran yang sama.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan data siswa
|
||||||
|
$siswa = new Siswa();
|
||||||
|
$siswa->user_id = $userId;
|
||||||
|
$siswa->sekolah_id = $sekolahId;
|
||||||
|
$siswa->kelas_id = $kelasId;
|
||||||
|
$siswa->tahun_ajaran_id = $tahunAjaranId;
|
||||||
|
|
||||||
|
if ($siswa->save()) {
|
||||||
|
toastr()->success('Data siswa berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data siswa.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('siswa')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatesiswa(Request $request, $id)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'user_id' => 'required|exists:users,id',
|
||||||
|
'sekolah_id' => 'required|exists:sekolahs,id',
|
||||||
|
'kelas_id' => 'required|exists:kelas,id',
|
||||||
|
'tahun_ajaran_id' => 'required|exists:tahun_ajarans,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cari data siswa berdasarkan ID
|
||||||
|
$siswa = Siswa::findOrFail($id);
|
||||||
|
|
||||||
|
$userId = $request->input('user_id');
|
||||||
|
$sekolahId = $request->input('sekolah_id');
|
||||||
|
$kelasId = $request->input('kelas_id');
|
||||||
|
$tahunAjaranId = $request->input('tahun_ajaran_id');
|
||||||
|
|
||||||
|
// Cek apakah siswa ini sudah terdaftar di sekolah, kelas, dan tahun ajaran yang sama, kecuali untuk siswa yang sedang di-update
|
||||||
|
$duplikat = Siswa::where('user_id', $userId)
|
||||||
|
->where('sekolah_id', $sekolahId)
|
||||||
|
->where('kelas_id', $kelasId)
|
||||||
|
->where('tahun_ajaran_id', $tahunAjaranId)
|
||||||
|
->where('id', '!=', $id) // Hindari memeriksa siswa yang sedang di-update
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikat) {
|
||||||
|
toastr()->error('Siswa tersebut sudah terdaftar di sekolah, kelas, dan tahun ajaran yang sama.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update data siswa
|
||||||
|
$siswa->user_id = $userId;
|
||||||
|
$siswa->sekolah_id = $sekolahId;
|
||||||
|
$siswa->kelas_id = $kelasId;
|
||||||
|
$siswa->tahun_ajaran_id = $tahunAjaranId;
|
||||||
|
|
||||||
|
if ($siswa->save()) {
|
||||||
|
toastr()->success('Data siswa berhasil di-update.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal meng-update data siswa.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('siswa');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapussiswa($id)
|
||||||
|
{
|
||||||
|
$siswa = Siswa::findOrFail($id);
|
||||||
|
$siswa->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data siswa berhasil dihapus.');
|
||||||
|
return redirect()->route('siswa');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadsiswa()
|
||||||
|
{
|
||||||
|
// Ambil data siswa dengan relasi lengkap untuk PDF
|
||||||
|
$siswas = Siswa::with('user', 'sekolah', 'kelas', 'tahunAjaran')->get();
|
||||||
|
$pdf = Pdf::loadView('admin.siswapdf', compact('siswas'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_siswa.pdf');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Kriteria;
|
||||||
|
use App\Models\Subkriteria;
|
||||||
|
use App\Models\Crip;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class SubkriteriaController extends Controller
|
||||||
|
{
|
||||||
|
public function subkriteria()
|
||||||
|
{
|
||||||
|
$subkriterias = Subkriteria::with('kriteria.kurikulum')->get();
|
||||||
|
$kriterias = Kriteria::with('kurikulum')->get();
|
||||||
|
return view('admin.subkriteria', compact('subkriterias', 'kriterias'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function tambahsubkriteria(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'kriteria_id' => 'required|exists:kriterias,id',
|
||||||
|
'pertanyaan' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pertanyaan = $request->input('pertanyaan');
|
||||||
|
|
||||||
|
// Cek apakah ada subkriteria dengan pertanyaan yang duplikat, tanpa memperhatikan kriteria
|
||||||
|
$duplikatPertanyaan = Subkriteria::where('pertanyaan', $pertanyaan)->exists();
|
||||||
|
|
||||||
|
if ($duplikatPertanyaan) {
|
||||||
|
toastr()->error('Subkriteria dengan pertanyaan tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$subkriteria = new Subkriteria();
|
||||||
|
$subkriteria->kriteria_id = $request->kriteria_id;
|
||||||
|
$subkriteria->pertanyaan = $pertanyaan;
|
||||||
|
|
||||||
|
if ($subkriteria->save()) {
|
||||||
|
toastr()->success('Data subkriteria berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data subkriteria.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('subkriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function updatesubkriteria(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'kriteria_id' => 'required|exists:kriterias,id',
|
||||||
|
'pertanyaan' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pertanyaan = $request->input('pertanyaan');
|
||||||
|
|
||||||
|
// Cek apakah ada pertanyaan yang duplikat di subkriteria lain (kecuali yang sedang diedit)
|
||||||
|
$duplikatPertanyaan = Subkriteria::where('pertanyaan', $pertanyaan)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($duplikatPertanyaan) {
|
||||||
|
toastr()->error('Subkriteria dengan pertanyaan tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$subkriteria = Subkriteria::findOrFail($id);
|
||||||
|
$subkriteria->kriteria_id = $request->kriteria_id;
|
||||||
|
$subkriteria->pertanyaan = $pertanyaan;
|
||||||
|
|
||||||
|
if ($subkriteria->save()) {
|
||||||
|
toastr()->success('Data subkriteria berhasil diperbarui.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data subkriteria.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('subkriteria')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapussubkriteria($id)
|
||||||
|
{
|
||||||
|
$subkriteria = Subkriteria::findOrFail($id);
|
||||||
|
$subkriteria->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data subkriteria berhasil dihapus.');
|
||||||
|
return redirect()->route('subkriteria');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadsubkriteria()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$subkriterias = Subkriteria::all();
|
||||||
|
$pdf = Pdf::loadView('admin.subkriteriapdf', compact('subkriterias'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_subkriteria.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\TahunAjaran;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class TahunAjaranController extends Controller
|
||||||
|
{
|
||||||
|
public function tahunajaran()
|
||||||
|
{
|
||||||
|
$tahunAjarans = TahunAjaran::orderBy('tanggal_mulai', 'desc')->get();
|
||||||
|
return view('admin.tahunajaran', compact('tahunAjarans'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahtahunajaran(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'tanggal_mulai' => 'required|date',
|
||||||
|
'tanggal_selesai' => 'required|date|after:tanggal_mulai',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
$tanggalMulai = $request->input('tanggal_mulai');
|
||||||
|
$tanggalSelesai = $request->input('tanggal_selesai');
|
||||||
|
|
||||||
|
// Cek apakah nama tahun ajaran sudah ada
|
||||||
|
$duplikatNama = TahunAjaran::where('nama', $nama)->exists();
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Tahun ajaran dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek overlap tanggal dengan tahun ajaran lain
|
||||||
|
$overlap = TahunAjaran::where(function($query) use ($tanggalMulai, $tanggalSelesai) {
|
||||||
|
$query->whereBetween('tanggal_mulai', [$tanggalMulai, $tanggalSelesai])
|
||||||
|
->orWhereBetween('tanggal_selesai', [$tanggalMulai, $tanggalSelesai])
|
||||||
|
->orWhere(function($q) use ($tanggalMulai, $tanggalSelesai) {
|
||||||
|
$q->where('tanggal_mulai', '<=', $tanggalMulai)
|
||||||
|
->where('tanggal_selesai', '>=', $tanggalSelesai);
|
||||||
|
});
|
||||||
|
})->exists();
|
||||||
|
|
||||||
|
if ($overlap) {
|
||||||
|
toastr()->error('Periode tahun ajaran bertumpang tindih dengan tahun ajaran yang sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$tahunAjaran = new TahunAjaran();
|
||||||
|
$tahunAjaran->nama = $nama;
|
||||||
|
$tahunAjaran->tanggal_mulai = $tanggalMulai;
|
||||||
|
$tahunAjaran->tanggal_selesai = $tanggalSelesai;
|
||||||
|
$tahunAjaran->is_active = $request->has('is_active') ? true : false;
|
||||||
|
|
||||||
|
// Jika set sebagai aktif, nonaktifkan yang lain
|
||||||
|
if ($tahunAjaran->is_active) {
|
||||||
|
TahunAjaran::where('is_active', true)->update(['is_active' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tahunAjaran->save()) {
|
||||||
|
toastr()->success('Data tahun ajaran berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data tahun ajaran.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('tahunajaran');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatetahunajaran(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'nama' => 'required|string|max:255',
|
||||||
|
'tanggal_mulai' => 'required|date',
|
||||||
|
'tanggal_selesai' => 'required|date|after:tanggal_mulai',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tahunAjaran = TahunAjaran::findOrFail($id);
|
||||||
|
|
||||||
|
$nama = $request->input('nama');
|
||||||
|
$tanggalMulai = $request->input('tanggal_mulai');
|
||||||
|
$tanggalSelesai = $request->input('tanggal_selesai');
|
||||||
|
|
||||||
|
// Cek duplikasi nama (kecuali yang sedang diedit)
|
||||||
|
$duplikatNama = TahunAjaran::where('nama', $nama)
|
||||||
|
->where('id', '!=', $id)
|
||||||
|
->exists();
|
||||||
|
if ($duplikatNama) {
|
||||||
|
toastr()->error('Tahun ajaran dengan nama tersebut sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek overlap tanggal (kecuali yang sedang diedit)
|
||||||
|
$overlap = TahunAjaran::where('id', '!=', $id)
|
||||||
|
->where(function($query) use ($tanggalMulai, $tanggalSelesai) {
|
||||||
|
$query->whereBetween('tanggal_mulai', [$tanggalMulai, $tanggalSelesai])
|
||||||
|
->orWhereBetween('tanggal_selesai', [$tanggalMulai, $tanggalSelesai])
|
||||||
|
->orWhere(function($q) use ($tanggalMulai, $tanggalSelesai) {
|
||||||
|
$q->where('tanggal_mulai', '<=', $tanggalMulai)
|
||||||
|
->where('tanggal_selesai', '>=', $tanggalSelesai);
|
||||||
|
});
|
||||||
|
})->exists();
|
||||||
|
|
||||||
|
if ($overlap) {
|
||||||
|
toastr()->error('Periode tahun ajaran bertumpang tindih dengan tahun ajaran yang sudah ada.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jika diset sebagai aktif, nonaktifkan yang lain
|
||||||
|
$isActive = $request->has('is_active') ? true : false;
|
||||||
|
if ($isActive) {
|
||||||
|
TahunAjaran::where('is_active', true)->where('id', '!=', $id)->update(['is_active' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tahunAjaran->nama = $nama;
|
||||||
|
$tahunAjaran->tanggal_mulai = $tanggalMulai;
|
||||||
|
$tahunAjaran->tanggal_selesai = $tanggalSelesai;
|
||||||
|
$tahunAjaran->is_active = $isActive;
|
||||||
|
|
||||||
|
if ($tahunAjaran->save()) {
|
||||||
|
toastr()->success('Data tahun ajaran berhasil diupdate.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data tahun ajaran.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('tahunajaran')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hapustahunajaran($id)
|
||||||
|
{
|
||||||
|
$tahunAjaran = TahunAjaran::findOrFail($id);
|
||||||
|
|
||||||
|
// Cek apakah tahun ajaran ini sedang digunakan oleh siswa
|
||||||
|
if ($tahunAjaran->siswas()->count() > 0) {
|
||||||
|
toastr()->error('Tahun ajaran tidak dapat dihapus karena masih digunakan oleh data siswa.');
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$tahunAjaran->delete();
|
||||||
|
|
||||||
|
toastr()->success('Data tahun ajaran berhasil dihapus.');
|
||||||
|
return redirect()->route('tahunajaran');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadtahunajaran()
|
||||||
|
{
|
||||||
|
$tahunAjarans = TahunAjaran::orderBy('tanggal_mulai', 'desc')->get();
|
||||||
|
$pdf = Pdf::loadView('admin.tahunajaranpdf', compact('tahunAjarans'));
|
||||||
|
return $pdf->download('data_tahun_ajaran.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setaktif($id)
|
||||||
|
{
|
||||||
|
// Nonaktifkan semua tahun ajaran
|
||||||
|
TahunAjaran::where('is_active', true)->update(['is_active' => false]);
|
||||||
|
|
||||||
|
// Aktifkan tahun ajaran yang dipilih
|
||||||
|
$tahunAjaran = TahunAjaran::findOrFail($id);
|
||||||
|
$tahunAjaran->is_active = true;
|
||||||
|
$tahunAjaran->save();
|
||||||
|
|
||||||
|
toastr()->success('Tahun ajaran berhasil diaktifkan.');
|
||||||
|
return redirect()->route('tahunajaran');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\User;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
|
||||||
|
class UserController extends Controller
|
||||||
|
{
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
$users = User::where('usertype', 'user')->get();
|
||||||
|
return view('admin.user', compact('users'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tambahuser(Request $request)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'name' => 'required',
|
||||||
|
'email' => 'required|email|unique:users,email', // Pastikan email unik
|
||||||
|
]);
|
||||||
|
|
||||||
|
// CEK ADMIN - BAGIAN YANG DITAMBAH
|
||||||
|
if ($request->input('usertype') == 'admin') {
|
||||||
|
$adminExists = User::where('usertype', 'admin')->exists();
|
||||||
|
if ($adminExists) {
|
||||||
|
toastr()->error('Admin sudah ada! Tidak bisa menambah admin lagi.');
|
||||||
|
return redirect()->route('user');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $request->input('name');
|
||||||
|
$email = $request->input('email');
|
||||||
|
|
||||||
|
// Membuat user baru dengan password default dan usertype
|
||||||
|
$user = new User();
|
||||||
|
$user->name = $name;
|
||||||
|
$user->email = $email;
|
||||||
|
$user->password = bcrypt('1234567890'); // Password default
|
||||||
|
$user->usertype = $request->input('usertype', 'user'); // Usertype otomatis, fallback ke 'user' jika tidak ada input
|
||||||
|
|
||||||
|
// Simpan data user
|
||||||
|
if ($user->save()) {
|
||||||
|
toastr()->success('Data user berhasil ditambahkan.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal menambahkan data user.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateuser(Request $request, $id)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'name' => 'required',
|
||||||
|
'email' => 'required|email|unique:users,email,' . $id, // Pastikan email unik, kecuali untuk user yang sedang diupdate
|
||||||
|
'password' => 'nullable|min:6', // Validasi password jika diisi
|
||||||
|
'usertype' => 'required' // Pastikan usertype ada
|
||||||
|
]);
|
||||||
|
|
||||||
|
// CEK ADMIN - BAGIAN YANG DITAMBAH
|
||||||
|
if ($request->input('usertype') == 'admin') {
|
||||||
|
// Cek apakah sudah ada admin lain (selain user yang sedang diupdate)
|
||||||
|
$adminExists = User::where('usertype', 'admin')->where('id', '!=', $id)->exists();
|
||||||
|
if ($adminExists) {
|
||||||
|
toastr()->error('Admin sudah ada! Tidak bisa mengubah user lain menjadi admin.');
|
||||||
|
return redirect()->route('user');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cari user yang akan diupdate berdasarkan ID
|
||||||
|
$user = User::find($id);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
toastr()->error('User tidak ditemukan.');
|
||||||
|
return redirect()->route('user');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update data user
|
||||||
|
$user->name = $request->input('name');
|
||||||
|
$user->email = $request->input('email');
|
||||||
|
$user->usertype = $request->input('usertype'); // Update usertype
|
||||||
|
|
||||||
|
// Jika ada password baru yang diinput, update password-nya
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
$user->password = bcrypt($request->input('password')); // Password baru jika diisi
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan perubahan
|
||||||
|
if ($user->save()) {
|
||||||
|
toastr()->success('Data user berhasil diperbarui.');
|
||||||
|
} else {
|
||||||
|
toastr()->error('Gagal memperbarui data user.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('user')->with('reload', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function hapususer($id)
|
||||||
|
{
|
||||||
|
// Cari user berdasarkan ID
|
||||||
|
$user = User::findOrFail($id);
|
||||||
|
|
||||||
|
// Hapus data user
|
||||||
|
$user->delete();
|
||||||
|
|
||||||
|
// Berikan notifikasi sukses
|
||||||
|
toastr()->success('Data user berhasil dihapus.');
|
||||||
|
|
||||||
|
// Redirect kembali ke halaman user
|
||||||
|
return redirect()->route('user');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function downloaduser()
|
||||||
|
{
|
||||||
|
// Ambil data sekolah dari database
|
||||||
|
$users = User::all();
|
||||||
|
$pdf = Pdf::loadView('admin.userpdf', compact('users'));
|
||||||
|
// Download file PDF
|
||||||
|
return $pdf->download('data_user.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class Admin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (Auth::user()->usertype !== 'admin') {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Lockout;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class LoginRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'email' => ['required', 'string', 'email'],
|
||||||
|
'password' => ['required', 'string'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to authenticate the request's credentials.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
public function authenticate(): void
|
||||||
|
{
|
||||||
|
$this->ensureIsNotRateLimited();
|
||||||
|
|
||||||
|
if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
|
||||||
|
RateLimiter::hit($this->throttleKey());
|
||||||
|
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'email' => trans('auth.failed'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
RateLimiter::clear($this->throttleKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the login request is not rate limited.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
public function ensureIsNotRateLimited(): void
|
||||||
|
{
|
||||||
|
if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new Lockout($this));
|
||||||
|
|
||||||
|
$seconds = RateLimiter::availableIn($this->throttleKey());
|
||||||
|
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'email' => trans('auth.throttle', [
|
||||||
|
'seconds' => $seconds,
|
||||||
|
'minutes' => ceil($seconds / 60),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the rate limiting throttle key for the request.
|
||||||
|
*/
|
||||||
|
public function throttleKey(): string
|
||||||
|
{
|
||||||
|
return Str::transliterate(Str::lower($this->string('email')).'|'.$this->ip());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class ProfileUpdateRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'lowercase',
|
||||||
|
'email',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique(User::class)->ignore($this->user()->id),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Alternatif extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'nama',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
public function mapels()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Mapel::class, 'alternatif_mapel');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kurikulum()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kurikulum::class, 'kurikulum_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function opsisubkriterias()
|
||||||
|
{
|
||||||
|
return $this->hasMany(OpsiSubkriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasilsaw()
|
||||||
|
{
|
||||||
|
return $this->hasMany(HasilSaw::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Crip extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'nama',
|
||||||
|
'nilai',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Relasi ke OpsiSubkriteria
|
||||||
|
public function opsisubkriterias()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Opsisubkriteria::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DetailSaw extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'hasil_saw_id',
|
||||||
|
'kriteria_id',
|
||||||
|
'subkriteria_id',
|
||||||
|
'opsi_subkriteria_id',
|
||||||
|
'nilai_normalisasi',
|
||||||
|
'nilai_bobot',
|
||||||
|
'skor_akhir'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'nilai_normalisasi' => 'float',
|
||||||
|
'nilai_bobot' => 'float',
|
||||||
|
'skor_akhir' => 'float'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function opsisubkriteria()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(OpsiSubkriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasilsaw()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(HasilSaw::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kriteria()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subkriteria()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Subkriteria::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class HasilSaw extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'sesi_kuis_id',
|
||||||
|
'alternatif_id',
|
||||||
|
'total_skor',
|
||||||
|
'skor_normalisasi',
|
||||||
|
'peringkat'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'total_skor' => 'float',
|
||||||
|
'skor_normalisasi' => 'float'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function sesikuis()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SesiKuis::class, 'sesi_kuis_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alternatif()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Alternatif::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detailsaw()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DetailSaw::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class JawabanKuis extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'sesi_kuis_id',
|
||||||
|
'subkriteria_id',
|
||||||
|
'opsi_dipilih'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function sesikuis()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SesiKuis::class, 'sesi_kuis_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subkriteria()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Subkriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Kelas extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['sekolah_id', 'nama_kelas' ];
|
||||||
|
|
||||||
|
public function sekolah()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Sekolah::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function siswas()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Siswa::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Kriteria extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'nama',
|
||||||
|
'jenis',
|
||||||
|
'bobot',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function kurikulum()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kurikulum::class, 'kurikulum_id');
|
||||||
|
}
|
||||||
|
public function subkriterias()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Subkriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detailsaw()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DetailSaw::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Kurikulum extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'nama',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mapels()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Mapel::class);
|
||||||
|
}
|
||||||
|
public function alternatifs()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Alternatif::class);
|
||||||
|
}
|
||||||
|
public function kriterias()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Kriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sesikuis()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SesiKuis::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Mapel extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'kurikulum_id',
|
||||||
|
'nama',
|
||||||
|
'kategori',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function kurikulum()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kurikulum::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alternatif()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Alternatif::class, 'alternatif_mapel');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class OpsiSubkriteria extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'opsisubkriterias';
|
||||||
|
protected $fillable = [
|
||||||
|
'subkriteria_id',
|
||||||
|
'alternatif_id',
|
||||||
|
'crips_id',
|
||||||
|
'opsi',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function subkriteria()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Subkriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function crips()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Crip::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alternatif()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Alternatif::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detailSaw()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DetailSaw::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Sekolah extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['nama', 'alamat'];
|
||||||
|
|
||||||
|
public function kelas()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Kelas::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function siswas()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Siswa::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SesiKuis extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'kurikulum_id',
|
||||||
|
'nama',
|
||||||
|
'sekolah',
|
||||||
|
'kelas',
|
||||||
|
'selesai_pada'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'selesai_pada' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kurikulum()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kurikulum::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jawabankuis()
|
||||||
|
{
|
||||||
|
return $this->hasMany(JawabanKuis::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasilsaw()
|
||||||
|
{
|
||||||
|
return $this->hasMany(HasilSaw::class)->orderBy('peringkat');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sudahselesai()
|
||||||
|
{
|
||||||
|
return !is_null($this->selesai_pada);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tandaiselesai()
|
||||||
|
{
|
||||||
|
$this->selesai_pada = now();
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
class Siswa extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'sekolah_id',
|
||||||
|
'kelas_id',
|
||||||
|
'tahun_ajaran_id' // TAMBAH INI
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sekolah(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Sekolah::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function kelas(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kelas::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tahunAjaran(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(TahunAjaran::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Subkriteria extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'kriteria_id',
|
||||||
|
'pertanyaan',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function kriteria()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Kriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function opsisubkriterias()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Opsisubkriteria::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jawabankuis()
|
||||||
|
{
|
||||||
|
return $this->hasMany(JawabanKuis::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detailsaw()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DetailSaw::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class SystemSetting extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['key', 'value', 'description'];
|
||||||
|
|
||||||
|
// Konstanta untuk key setting
|
||||||
|
const PERHITUNGAN_OPEN = 'perhitungan_open';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cek apakah perhitungan/quiz terbuka
|
||||||
|
*/
|
||||||
|
public static function isPerhitunganOpen()
|
||||||
|
{
|
||||||
|
// Gunakan cache untuk performa yang lebih baik
|
||||||
|
return Cache::remember('perhitungan_open', 60, function () {
|
||||||
|
$setting = self::where('key', self::PERHITUNGAN_OPEN)->first();
|
||||||
|
return $setting ? (bool) $setting->value : false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update status perhitungan/quiz
|
||||||
|
*/
|
||||||
|
public static function setPerhitunganOpen($status)
|
||||||
|
{
|
||||||
|
$setting = self::updateOrCreate(
|
||||||
|
['key' => self::PERHITUNGAN_OPEN],
|
||||||
|
[
|
||||||
|
'value' => $status ? '1' : '0',
|
||||||
|
'description' => 'Status akses section perhitungan/quiz untuk user'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clear cache
|
||||||
|
Cache::forget('perhitungan_open');
|
||||||
|
|
||||||
|
return $setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle status perhitungan/quiz
|
||||||
|
*/
|
||||||
|
public static function togglePerhitunganOpen()
|
||||||
|
{
|
||||||
|
$currentStatus = self::isPerhitunganOpen();
|
||||||
|
$newStatus = !$currentStatus;
|
||||||
|
|
||||||
|
self::setPerhitunganOpen($newStatus);
|
||||||
|
|
||||||
|
return $newStatus;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
|
class TahunAjaran extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'nama',
|
||||||
|
'tanggal_mulai',
|
||||||
|
'tanggal_selesai',
|
||||||
|
'is_active'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'tanggal_mulai' => 'date',
|
||||||
|
'tanggal_selesai' => 'date',
|
||||||
|
'is_active' => 'boolean'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function siswas(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Siswa::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeActive($query)
|
||||||
|
{
|
||||||
|
return $query->where('is_active', true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?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 App\Notifications\ResetPasswordNotification;
|
||||||
|
use App\Notifications\BrevoResetPassword;
|
||||||
|
|
||||||
|
class User extends Authenticatable
|
||||||
|
{
|
||||||
|
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||||
|
use HasFactory, Notifiable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be hidden for serialization.
|
||||||
|
*
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
protected $hidden = [
|
||||||
|
'password',
|
||||||
|
'remember_token',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'email_verified_at' => 'datetime',
|
||||||
|
'password' => 'hashed',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function siswa()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Siswa::class); // satu user hanya punya satu data siswa
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sesikuis()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SesiKuis::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override default reset password notification
|
||||||
|
*/
|
||||||
|
public function sendPasswordResetNotification($token)
|
||||||
|
{
|
||||||
|
$this->notify(new BrevoResetPassword($token, $this->email));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
|
class BrevoResetPassword extends Notification
|
||||||
|
{
|
||||||
|
public $token;
|
||||||
|
public $email;
|
||||||
|
|
||||||
|
public function __construct($token, $email)
|
||||||
|
{
|
||||||
|
$this->token = $token;
|
||||||
|
$this->email = $email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via($notifiable)
|
||||||
|
{
|
||||||
|
return ['mail']; // WAJIB: pakai channel yang valid
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail($notifiable)
|
||||||
|
{
|
||||||
|
$resetUrl = URL::temporarySignedRoute(
|
||||||
|
'password.reset',
|
||||||
|
Carbon::now()->addMinutes(60),
|
||||||
|
['token' => $this->token, 'email' => $this->email]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Kirim langsung lewat Brevo API
|
||||||
|
Http::withHeaders([
|
||||||
|
'api-key' => env('BREVO_API_KEY'),
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'accept' => 'application/json',
|
||||||
|
])->post('https://api.brevo.com/v3/smtp/email', [
|
||||||
|
'sender' => [
|
||||||
|
'name' => 'Pintera Website',
|
||||||
|
'email' => 'agya.rwildanti@gmail.com' // HARUS diverifikasi di Brevo
|
||||||
|
],
|
||||||
|
'to' => [
|
||||||
|
['email' => $this->email],
|
||||||
|
],
|
||||||
|
'subject' => 'Reset Password Aplikasi Kamu',
|
||||||
|
'htmlContent' => "
|
||||||
|
<p>Klik link berikut untuk mereset password:</p>
|
||||||
|
<p><a href='{$resetUrl}'>Reset Password</a></p>
|
||||||
|
<p>Link berlaku 60 menit.</p>
|
||||||
|
",
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Return dummy MailMessage agar Laravel tidak error
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject('Reset Password sedang diproses...')
|
||||||
|
->line('Link reset sudah dikirim ke email Anda.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class ResetPasswordNotification extends Notification
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*/
|
||||||
|
public function toMail(object $notifiable): MailMessage
|
||||||
|
{
|
||||||
|
return (new MailMessage)
|
||||||
|
->line('The introduction to the notification.')
|
||||||
|
->action('Notification Action', url('/'))
|
||||||
|
->line('Thank you for using our application!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array representation of the notification.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(object $notifiable): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components;
|
||||||
|
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class AppLayout extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the view / contents that represents the component.
|
||||||
|
*/
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('layouts.app');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components;
|
||||||
|
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class GuestLayout extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the view / contents that represents the component.
|
||||||
|
*/
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('layouts.guest');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Application;
|
||||||
|
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...
|
||||||
|
/** @var Application $app */
|
||||||
|
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||||
|
|
||||||
|
$status = $app->handleCommand(new ArgvInput);
|
||||||
|
|
||||||
|
exit($status);
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?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',
|
||||||
|
commands: __DIR__.'/../routes/console.php',
|
||||||
|
health: '/up',
|
||||||
|
)
|
||||||
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
|
$middleware->alias([
|
||||||
|
'admin' => \App\Http\Middleware\Admin::class,
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
->withExceptions(function (Exceptions $exceptions) {
|
||||||
|
//
|
||||||
|
})->create();
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
App\Providers\AppServiceProvider::class,
|
||||||
|
];
|
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
"$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",
|
||||||
|
"barryvdh/laravel-dompdf": "^3.1",
|
||||||
|
"laravel/framework": "^12.0",
|
||||||
|
"laravel/tinker": "^2.10.1",
|
||||||
|
"php-flasher/flasher-toastr-laravel": "^2.1",
|
||||||
|
"php-flasher/flasher-toastr-symfony": "^2.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"fakerphp/faker": "^1.23",
|
||||||
|
"laravel/breeze": "^2.3",
|
||||||
|
"laravel/pail": "^1.2.2",
|
||||||
|
"laravel/pint": "^1.13",
|
||||||
|
"laravel/sail": "^1.41",
|
||||||
|
"mockery/mockery": "^1.6",
|
||||||
|
"nunomaduro/collision": "^8.6",
|
||||||
|
"pestphp/pest": "^3.8",
|
||||||
|
"pestphp/pest-plugin-laravel": "^3.2"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"@php artisan config:clear --ansi",
|
||||||
|
"@php artisan test"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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' => 'Asia/Jakarta',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| 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,174 @@
|
||||||
|
<?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', 'pintera'),
|
||||||
|
'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_'),
|
||||||
|
'persistent' => env('REDIS_PERSISTENT', false),
|
||||||
|
],
|
||||||
|
|
||||||
|
'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,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,
|
||||||
|
'handler_with' => [
|
||||||
|
'stream' => 'php://stderr',
|
||||||
|
],
|
||||||
|
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||||
|
'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,118 @@
|
||||||
|
<?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',
|
||||||
|
],
|
||||||
|
'retry_after' => 60,
|
||||||
|
],
|
||||||
|
|
||||||
|
'roundrobin' => [
|
||||||
|
'transport' => 'roundrobin',
|
||||||
|
'mailers' => [
|
||||||
|
'ses',
|
||||||
|
'postmark',
|
||||||
|
],
|
||||||
|
'retry_after' => 60,
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| 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,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 @@
|
||||||
|
*.sqlite*
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||||
|
*/
|
||||||
|
class UserFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The current password being used by the factory.
|
||||||
|
*/
|
||||||
|
protected static ?string $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => fake()->name(),
|
||||||
|
'email' => fake()->unique()->safeEmail(),
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
'password' => static::$password ??= Hash::make('password'),
|
||||||
|
'remember_token' => Str::random(10),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate that the model's email address should be unverified.
|
||||||
|
*/
|
||||||
|
public function unverified(): static
|
||||||
|
{
|
||||||
|
return $this->state(fn (array $attributes) => [
|
||||||
|
'email_verified_at' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('users', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('email')->unique();
|
||||||
|
$table->timestamp('email_verified_at')->nullable();
|
||||||
|
$table->string('password');
|
||||||
|
$table->rememberToken();
|
||||||
|
$table->string('usertype')->default('user');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||||
|
$table->string('email')->primary();
|
||||||
|
$table->string('token');
|
||||||
|
$table->timestamp('created_at')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('sessions', function (Blueprint $table) {
|
||||||
|
$table->string('id')->primary();
|
||||||
|
$table->foreignId('user_id')->nullable()->index();
|
||||||
|
$table->string('ip_address', 45)->nullable();
|
||||||
|
$table->text('user_agent')->nullable();
|
||||||
|
$table->longText('payload');
|
||||||
|
$table->integer('last_activity')->index();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
Schema::dropIfExists('password_reset_tokens');
|
||||||
|
Schema::dropIfExists('sessions');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('cache', function (Blueprint $table) {
|
||||||
|
$table->string('key')->primary();
|
||||||
|
$table->mediumText('value');
|
||||||
|
$table->integer('expiration');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('cache_locks', function (Blueprint $table) {
|
||||||
|
$table->string('key')->primary();
|
||||||
|
$table->string('owner');
|
||||||
|
$table->integer('expiration');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('cache');
|
||||||
|
Schema::dropIfExists('cache_locks');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('jobs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('queue')->index();
|
||||||
|
$table->longText('payload');
|
||||||
|
$table->unsignedTinyInteger('attempts');
|
||||||
|
$table->unsignedInteger('reserved_at')->nullable();
|
||||||
|
$table->unsignedInteger('available_at');
|
||||||
|
$table->unsignedInteger('created_at');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('job_batches', function (Blueprint $table) {
|
||||||
|
$table->string('id')->primary();
|
||||||
|
$table->string('name');
|
||||||
|
$table->integer('total_jobs');
|
||||||
|
$table->integer('pending_jobs');
|
||||||
|
$table->integer('failed_jobs');
|
||||||
|
$table->longText('failed_job_ids');
|
||||||
|
$table->mediumText('options')->nullable();
|
||||||
|
$table->integer('cancelled_at')->nullable();
|
||||||
|
$table->integer('created_at');
|
||||||
|
$table->integer('finished_at')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('uuid')->unique();
|
||||||
|
$table->text('connection');
|
||||||
|
$table->text('queue');
|
||||||
|
$table->longText('payload');
|
||||||
|
$table->longText('exception');
|
||||||
|
$table->timestamp('failed_at')->useCurrent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('jobs');
|
||||||
|
Schema::dropIfExists('job_batches');
|
||||||
|
Schema::dropIfExists('failed_jobs');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('tahun_ajarans', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama'); // contoh: "2024/2025"
|
||||||
|
$table->date('tanggal_mulai');
|
||||||
|
$table->date('tanggal_selesai');
|
||||||
|
$table->boolean('is_active')->default(false);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('tahun_ajarans');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('sekolahs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama')->unique();
|
||||||
|
$table->string('alamat')->unique();
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('sekolahs');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('kelas', function (Blueprint $table) {
|
||||||
|
$table->id(); // This creates an auto-incrementing ID
|
||||||
|
$table->foreignId('sekolah_id')->constrained()->onDelete('cascade'); // Assumes 'sekolahs' table exists and has an 'id' column
|
||||||
|
$table->string('nama_kelas');
|
||||||
|
$table->timestamps(); // Creates 'created_at' and 'updated_at' timestamps
|
||||||
|
|
||||||
|
$table->unique(['nama_kelas', 'sekolah_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('kelas'); // Drops the 'kelas' table if the migration is rolled back
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('siswas', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
|
||||||
|
$table->foreignId('sekolah_id')->constrained('sekolahs')->onDelete('cascade');
|
||||||
|
$table->foreignId('kelas_id')->constrained('kelas')->onDelete('cascade');
|
||||||
|
$table->foreignId('tahun_ajaran_id')->constrained('tahun_ajarans')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('siswas');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('kurikulums', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama')->unique();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('kurikulums');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('mapels', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('kurikulum_id')->constrained('kurikulums')->onDelete('cascade');
|
||||||
|
$table->string('nama')->unique();
|
||||||
|
$table->enum('kategori', ['Mata Pelajaran Pilihan', 'Mata Pelajaran Wajib']);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('mapels');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('alternatifs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama')->unique();
|
||||||
|
$table->foreignId('kurikulum_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('alternatifs');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('alternatif_mapel', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('alternatif_id')->constrained('alternatifs')->onDelete('cascade');
|
||||||
|
$table->foreignId('mapel_id')->constrained('mapels')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('alternatif_mapel');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('kriterias', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama')->unique();
|
||||||
|
$table->enum('jenis', ['Benefit', 'Cost']);
|
||||||
|
$table->decimal('bobot', 3, 1);
|
||||||
|
$table->foreignId('kurikulum_id')->constrained('kurikulums')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('kriterias');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('subkriterias', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('kriteria_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->string('pertanyaan')->unique();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('subkriterias');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('crips', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama')->unique();
|
||||||
|
$table->integer('nilai')->unique();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('crips');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('opsisubkriterias', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('subkriteria_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('alternatif_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->string('opsi');
|
||||||
|
$table->foreignId('crips_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('opsisubkriterias');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('sesi_kuis', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||||
|
$table->foreignId('kurikulum_id')->constrained('kurikulums')->onDelete('cascade');
|
||||||
|
$table->string('nama');
|
||||||
|
$table->string('sekolah');
|
||||||
|
$table->string('kelas');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('sesi_kuis');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('jawaban_kuis', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('sesi_kuis_id')->constrained('sesi_kuis')->onDelete('cascade');
|
||||||
|
$table->foreignId('subkriteria_id')->constrained('subkriterias')->onDelete('cascade');
|
||||||
|
$table->string('opsi_dipilih');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('jawaban_kuis');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('hasil_saws', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('sesi_kuis_id')->constrained('sesi_kuis')->onDelete('cascade');
|
||||||
|
$table->foreignId('alternatif_id')->constrained('alternatifs')->onDelete('cascade');
|
||||||
|
$table->decimal('total_skor', 8, 4);
|
||||||
|
$table->decimal('skor_normalisasi', 8, 4);
|
||||||
|
$table->integer('peringkat');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('hasil_saws');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('sesi_kuis', function (Blueprint $table) {
|
||||||
|
$table->timestamp('selesai_pada')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('sesi_kuis', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('detail_saws', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('hasil_saw_id')->constrained('hasil_saws')->onDelete('cascade');
|
||||||
|
$table->foreignId('kriteria_id')->constrained('kriterias')->onDelete('cascade');
|
||||||
|
$table->foreignId('subkriteria_id')->constrained('subkriterias')->onDelete('cascade');
|
||||||
|
$table->foreignId('opsi_subkriteria_id')->constrained('opsisubkriterias')->onDelete('cascade');
|
||||||
|
$table->decimal('nilai_normalisasi', 8, 4);
|
||||||
|
$table->decimal('nilai_bobot', 8, 4);
|
||||||
|
$table->decimal('skor_akhir', 8, 4);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('detail_saws');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('kriterias', function (Blueprint $table) {
|
||||||
|
$table->decimal('bobot', 5, 2)->change(); // 5 total digit, 2 desimal
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('kriterias', function (Blueprint $table) {
|
||||||
|
$table->decimal('bobot', 3, 1)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('system_settings', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('key')->unique();
|
||||||
|
$table->text('value')->nullable();
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Insert default setting
|
||||||
|
DB::table('system_settings')->insert([
|
||||||
|
'key' => 'perhitungan_open',
|
||||||
|
'value' => '0', // Default tertutup
|
||||||
|
'description' => 'Status akses section perhitungan/quiz untuk user',
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('system_settings');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class DatabaseSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Seed the application's database.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// User::factory(10)->create();
|
||||||
|
|
||||||
|
User::factory()->create([
|
||||||
|
'name' => 'Test User',
|
||||||
|
'email' => 'test@example.com',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "vite build",
|
||||||
|
"dev": "vite"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/forms": "^0.5.2",
|
||||||
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
|
"alpinejs": "^3.4.2",
|
||||||
|
"autoprefixer": "^10.4.2",
|
||||||
|
"axios": "^1.8.2",
|
||||||
|
"concurrently": "^9.0.1",
|
||||||
|
"laravel-vite-plugin": "^1.2.0",
|
||||||
|
"postcss": "^8.4.31",
|
||||||
|
"tailwindcss": "^3.1.0",
|
||||||
|
"vite": "^6.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"select2": "^4.1.0-rc.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
colors="true"
|
||||||
|
>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Unit">
|
||||||
|
<directory>tests/Unit</directory>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="Feature">
|
||||||
|
<directory>tests/Feature</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
<source>
|
||||||
|
<include>
|
||||||
|
<directory>app</directory>
|
||||||
|
</include>
|
||||||
|
</source>
|
||||||
|
<php>
|
||||||
|
<env name="APP_ENV" value="testing"/>
|
||||||
|
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||||
|
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||||
|
<env name="CACHE_STORE" value="array"/>
|
||||||
|
<env name="DB_CONNECTION" value="sqlite"/>
|
||||||
|
<env name="DB_DATABASE" value=":memory:"/>
|
||||||
|
<env name="MAIL_MAILER" value="array"/>
|
||||||
|
<env name="PULSE_ENABLED" value="false"/>
|
||||||
|
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||||
|
<env name="SESSION_DRIVER" value="array"/>
|
||||||
|
<env name="TELESCOPE_ENABLED" value="false"/>
|
||||||
|
</php>
|
||||||
|
</phpunit>
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue