Compare commits
44 Commits
upload-vid
...
main
@ -1,66 +1,29 @@
|
||||
<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)**
|
||||
- **[WebReinvent](https://webreinvent.com/)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Jump24](https://jump24.co.uk)**
|
||||
- **[Redberry](https://redberry.international/laravel/)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
- **[byte5](https://byte5.de)**
|
||||
- **[OP.GG](https://op.gg)**
|
||||
|
||||
## 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).
|
||||
### Note: if you forgot how to open readme from vs code:
|
||||
- Ctrl K + V (Side bar readme)
|
||||
- Crtl Shift V (Full size read me)
|
||||
|
||||
# Laravel Tivi
|
||||
## Instalation
|
||||
- open /etc/php/8.2/fpm/php.ini
|
||||
- upload_max_filesize = 100M
|
||||
- post_max_size = 100M
|
||||
- Pull Project on server
|
||||
- Setting .env from .env.example
|
||||
- note: fill SANCTUM_LARAVEL_DOMAINS with frontend url
|
||||
- example: SANCTUM_STATEFUL_DOMAINS=[http://tv.bintangtechnology.com,https://tv.bintangtechnology.com,]
|
||||
- run command
|
||||
- sudo chmod -R 777 storage -> laravel storage log permission
|
||||
- php artisan storage:link -> if u use public storage in laravel, not s3
|
||||
- composer update {or} /usr/bin/php8.2 /usr/local/bin/composer update
|
||||
- php artisan migrate --seed {or} php8.2 artisan migrate --seed
|
||||
- php artisan key:generate {or} php artisan key:generate
|
||||
|
||||
- note:
|
||||
- usually, cors problem cause by chmod on /storage or upload_max_filesize / post_max_size (only happen when u debug with firefox)
|
||||
|
||||
## Update
|
||||
- open project loaction (ex: /var/www/api_tivi)
|
||||
- run command
|
||||
- git pull --all
|
||||
- composer install
|
||||
- php artisan migrate (if it has database changes)
|
||||
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Helper\Sts\Indokargo;
|
||||
use App\Models\StsLog;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StsReschedule extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'sts:reschedule';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Resschedule failed sts to sts data';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void {
|
||||
$sleep = 30; // 30 second
|
||||
while(true) {
|
||||
$this->info('---------------------------');
|
||||
$this->info('reschedule sts:' . Carbon::now()->toDateTimeString());
|
||||
$this->info('---------------------------');
|
||||
|
||||
// get reschedu;e sts logs
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$rescheduleStsLogs = StsLog::where(['is_retry' => true])->get();
|
||||
foreach($rescheduleStsLogs as $rescheduleStsLog) {
|
||||
try {
|
||||
$partner = $rescheduleStsLog->partner;
|
||||
$module = $rescheduleStsLog->module;
|
||||
$serviceName = $rescheduleStsLog->service_name;
|
||||
$request = new Request((array) $rescheduleStsLog->request_data ?? []);
|
||||
$localId = $rescheduleStsLog->local_id;
|
||||
$partnerId = $rescheduleStsLog->partner_id;
|
||||
$lastSeq = $rescheduleStsLog->seq;
|
||||
|
||||
if($partner == StsLog::PARTNER_INDOKARGO) {
|
||||
if($module == StsLog::MODULE_TV) {
|
||||
if($serviceName == StsLog::SERVICE_CREATE_TV_ADDRESS) {
|
||||
Indokargo::createTVAddress($request, $localId, $lastSeq);
|
||||
} else if($serviceName == StsLog::SERVICE_UPDATE_TV_ADDRESS) {
|
||||
Indokargo::updateTVAddress($request, $localId, $partnerId, $lastSeq);
|
||||
} else if($serviceName == StsLog::SERVICE_CHANGE_STATUS_TV_ADDRESS) {
|
||||
Indokargo::changeStatusAddress($request, $localId, $partnerId, $lastSeq);
|
||||
} else {
|
||||
throw new \Exception("Service name '$partner' > '$module' > '$serviceName' not found service");
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("Module name '$partner' > '$module' not found service");
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("Partner name '$partner' not found service");
|
||||
}
|
||||
$success++;
|
||||
} catch(\Throwable $th) {
|
||||
$failed++;
|
||||
$this->info("stsLog id: ". $rescheduleStsLog->id . " => " . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// save all retry request is retry false
|
||||
$rescheduleStsLogIds = $rescheduleStsLogs->pluck('id')->toArray();
|
||||
StsLog::whereIn('id', $rescheduleStsLogIds)->update(['is_retry' => false]);
|
||||
|
||||
$this->info('---------------------------');
|
||||
$this->info("result: $success success, $failed failed" );
|
||||
$this->info("Sleep in $sleep seconds" );
|
||||
$this->info('---------------------------');
|
||||
sleep($sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace App\Helper\Frontend;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Models\Tv;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Note:
|
||||
* if any of frontend component need specific api query / data specific.
|
||||
* Please add function to get data here.
|
||||
*
|
||||
* But, if the parent component still needs to pass the url to the
|
||||
* child component, the url api can be placed in the app/Http/Controllers/api/superadmin/GeneralController
|
||||
*/
|
||||
|
||||
class ApiUtilities {
|
||||
|
||||
// for components/app/tv/button/excel.vue
|
||||
public static function tvExcel(Request $request) {
|
||||
$request->validate(['a' => 'nullable|string']);
|
||||
|
||||
switch($request->a) {
|
||||
case 'excelTemplate':
|
||||
return Tv::getExcelTemplate();
|
||||
break;
|
||||
case 'validateData':
|
||||
$tvCodes = $request->tvCodes ?? [];
|
||||
$tvs = $request->tvs ?? [];
|
||||
$oValidation = TV::validateExcel($tvs, $tvCodes);
|
||||
return JSONResponse::Success(['oValidation' => $oValidation]);
|
||||
break;
|
||||
case 'uploadExcel':
|
||||
$tvCodes = $request->tvCodes ?? [];
|
||||
$tvs = $request->tvs ?? [];
|
||||
$oValidation = TV::validateExcel($tvs, $tvCodes);
|
||||
$result = TV::uploadExcel($tvs, $oValidation, $request->user());
|
||||
return JSONResponse::Success($result);
|
||||
break;
|
||||
case 'exportData':
|
||||
return Tv::getExportData($request);
|
||||
break;
|
||||
case 'excelDetail':
|
||||
return Tv::getExcelDetail($request);
|
||||
break;
|
||||
|
||||
}
|
||||
throw new \Exception('Invalid Request Command');
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,180 @@
|
||||
<?php
|
||||
namespace App\Helper\STS;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Models\StsLog;
|
||||
use App\Models\Tv;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class Indokargo {
|
||||
const STATUS_SUCCESS = 'Success';
|
||||
const STATUS_FAILURE = 'Failure';
|
||||
// const STATUS_WARNING = 'Warning';
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//-- UTILITIES
|
||||
private static function _checkIkResponse($res) {
|
||||
$status = $res['status'];
|
||||
if($res['status'] == self::STATUS_SUCCESS) return;
|
||||
else if($res['status'] == self::STATUS_FAILURE) {
|
||||
// note: Indokargo error message can be array or string
|
||||
$errorMessage = $res['error']['error_message'];
|
||||
if(is_array($errorMessage)) throw ValidationException::withMessages($errorMessage);
|
||||
else throw new \Exception($errorMessage);
|
||||
}
|
||||
else {
|
||||
throw new \Exception("Indokargo status is not valid (ik status = $status)" );
|
||||
}
|
||||
}
|
||||
private static function _HttpTransaction(StsLog $stsLog, $callback) {
|
||||
try {
|
||||
return $callback();
|
||||
} catch(ConnectionException $e) {
|
||||
// if error cause by connection error, try again later
|
||||
$stsLog->error_info = [
|
||||
'message' => $e->getMessage(),
|
||||
'errors' => $e->getTrace()
|
||||
];
|
||||
$stsLog->result = StsLog::STATUS_FAILED;
|
||||
$stsLog->is_retry = true;
|
||||
$stsLog->save();
|
||||
return JSONResponse::Success(['is_warning' => true,
|
||||
'message' => "Failed to sync data with indokargo data, don't worry, we will sync data later"]);
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollBack();
|
||||
$stsLog->error_info = [
|
||||
'message' => $th->getMessage(),
|
||||
'errors' => $th->getTrace()
|
||||
];
|
||||
$stsLog->result = StsLog::STATUS_FAILED;
|
||||
$stsLog->save();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
//-- END UTILITIES
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
public static function createTVAddress(Request $request, int $tvFk, int $lastSeq = 0) {
|
||||
$seq = $lastSeq + 1;
|
||||
|
||||
/**
|
||||
* local id = TV FK, partnerId = ik_address_id
|
||||
* Why not new tv request id as local_id?
|
||||
* - New Tv request data will be deleted after TV data is inserted into the local DB
|
||||
*/
|
||||
$stsLog = new StsLog();
|
||||
$stsLog->partner = StsLog::PARTNER_INDOKARGO;
|
||||
$stsLog->is_outgoing = true;
|
||||
$stsLog->module = StsLog::MODULE_TV;
|
||||
$stsLog->service_name = StsLog::SERVICE_CREATE_TV_ADDRESS;
|
||||
$stsLog->local_id = $tvFk;
|
||||
$stsLog->partner_id = null;
|
||||
$stsLog->seq = $seq;
|
||||
$stsLog->request_data = $request->all();
|
||||
$stsLog->request_time = Carbon::now();
|
||||
|
||||
return self::_HttpTransaction($stsLog, function() use($tvFk, $request, $stsLog) {
|
||||
$request->validate(['code' => 'required|string']);
|
||||
|
||||
$result = Http::indokargo()->post('tv/address/create', $request->all());
|
||||
$res = $result->throw()->json();
|
||||
|
||||
// update stsLog
|
||||
$stsLog->response_data = $res;
|
||||
$stsLog->response_time = Carbon::now();
|
||||
|
||||
self::_checkIkResponse($res);
|
||||
|
||||
$ikAddress = $res['data']['0'];
|
||||
$ikAddressId = $ikAddress['id'];
|
||||
$stsLog->partner_id = $ikAddressId;
|
||||
|
||||
// check ik address id is exist (almost impossible to happen, 0.01%)
|
||||
$isDuplicateIkAddressId = TV::where([
|
||||
['ik_address_id', '=', $ikAddressId],
|
||||
['id', '!=', $tvFk]
|
||||
])->first();
|
||||
if($isDuplicateIkAddressId) throw new \Exception("IK Address ID Already exist in current db ($ikAddressId)");
|
||||
|
||||
DB::beginTransaction();
|
||||
$tv = Tv::findOrFail($tvFk);
|
||||
$tv->ik_address_id = $ikAddressId;
|
||||
$tv->save();
|
||||
|
||||
$stsLog->result = StsLog::STATUS_SUCCESS;
|
||||
$stsLog->save();
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['is_warning' => false, 'message' => 'Success To Save Data']);
|
||||
});
|
||||
}
|
||||
|
||||
public static function updateTVAddress(Request $request, int $tvFk, String $ikAddressId, int $lastSeq = 0) {
|
||||
$seq = $lastSeq + 1;
|
||||
|
||||
$request->merge(['ik_address_id' => $ikAddressId]);
|
||||
$stsLog = new StsLog();
|
||||
$stsLog->partner = StsLog::PARTNER_INDOKARGO;
|
||||
$stsLog->is_outgoing = true;
|
||||
$stsLog->module = StsLog::MODULE_TV;
|
||||
$stsLog->service_name = StsLog::SERVICE_UPDATE_TV_ADDRESS;
|
||||
$stsLog->local_id = $tvFk;
|
||||
$stsLog->partner_id = $ikAddressId;
|
||||
$stsLog->seq = $seq;
|
||||
$stsLog->request_data = $request->all();
|
||||
$stsLog->request_time = Carbon::now();
|
||||
|
||||
return self::_HttpTransaction($stsLog, function() use($stsLog, $request) {
|
||||
$request->validate(['code' => 'required|string', 'ik_address_id' => 'required|string']);
|
||||
$result = Http::indokargo()->post('tv/address/update-tv', $request->all());
|
||||
$res = $result->throw()->json();
|
||||
|
||||
// update stsLog
|
||||
$stsLog->response_data = $res;
|
||||
$stsLog->response_time = Carbon::now();
|
||||
self::_checkIkResponse($res);
|
||||
$stsLog->result = StsLog::STATUS_SUCCESS;
|
||||
$stsLog->save();
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message' => "Success to save data"]);
|
||||
});
|
||||
}
|
||||
|
||||
public static function changeStatusAddress(Request $request, int $tvFk, String $ikAddressId, int $lastSeq = 0) {
|
||||
$seq = $lastSeq + 1;
|
||||
|
||||
$request->merge(['ik_address_id' => $ikAddressId]);
|
||||
$stsLog = new StsLog();
|
||||
$stsLog->partner = StsLog::PARTNER_INDOKARGO;
|
||||
$stsLog->is_outgoing = true;
|
||||
$stsLog->module = StsLog::MODULE_TV;
|
||||
$stsLog->service_name = StsLog::SERVICE_CHANGE_STATUS_TV_ADDRESS;
|
||||
$stsLog->local_id = $tvFk;
|
||||
$stsLog->partner_id = $request->ik_address_id;
|
||||
$stsLog->seq = $seq;
|
||||
$stsLog->request_data = $request->all();
|
||||
$stsLog->request_time = Carbon::now();
|
||||
|
||||
return self::_HttpTransaction($stsLog, function() use($stsLog, $request) {
|
||||
$request->validate(['ik_address_id' => 'required|string', 'is_active'=> 'required|boolean']);
|
||||
$result = Http::indokargo()->post('tv/address/change-status', $request->all());
|
||||
$res = $result->throw()->json();
|
||||
|
||||
// update stsLog
|
||||
$stsLog->response_data = $res;
|
||||
$stsLog->response_time = Carbon::now();
|
||||
self::_checkIkResponse($res);
|
||||
$stsLog->result = StsLog::STATUS_SUCCESS;
|
||||
$stsLog->save();
|
||||
DB::commit();
|
||||
|
||||
return JSONResponse::Success(['is_warning' => false, 'message' => 'Success To Change Status']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\mobile;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApkUpdate;
|
||||
use App\Models\VideoUpdate;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CheckUpdateController extends Controller {
|
||||
public function videoUpdateLatest(Request $request) {
|
||||
$lastestVideoUpdate = VideoUpdate::getLatestSelected();
|
||||
return JSONResponse::Success(['latestVideoUpload' => $lastestVideoUpdate]);
|
||||
}
|
||||
public function apkUpdateLatest(Request $request) {
|
||||
$latestApkUpdate = ApkUpdate::getLatest();
|
||||
return JSONResponse::Success(['latestApkUpdate' => $latestApkUpdate]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\mobile;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApkUpdate;
|
||||
use App\Models\NewTvRequest;
|
||||
use App\Models\Tv;
|
||||
use App\Models\VideoUpdate;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TvController extends Controller {
|
||||
public function newRequest(Request $request) {
|
||||
return NewTvRequest::checkOrCreateFromRequest($request);
|
||||
}
|
||||
|
||||
public function checkUpdate(Request $request) {
|
||||
$request->validate(['id' => 'nullable|integer',
|
||||
'apk_version_code' => 'required|integer',
|
||||
'apk_version_name' => 'required|string']);
|
||||
|
||||
$tv = null;
|
||||
$latestApkUpdate = null;
|
||||
$latestVideoUpdate = null;
|
||||
if($request->id) {
|
||||
$tv = Tv::find($request->id);
|
||||
$tv->last_connected_at = now();
|
||||
$tv->apk_version_code = $request->apk_version_code;
|
||||
$tv->apk_version_name = $request->apk_version_name;
|
||||
$tv->save();
|
||||
$latestApkUpdate = ApkUpdate::getLatest();
|
||||
$latestVideoUpdate = VideoUpdate::getLatestSelected();
|
||||
}
|
||||
|
||||
return JSONResponse::Success(['tv' => $tv, 'latestApkUpdate' => $latestApkUpdate, 'latestVideoUpdate' => $latestVideoUpdate]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin;
|
||||
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApkUpdate;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ApkUploadController extends Controller {
|
||||
public function init(Request $request) {
|
||||
$request->validate([
|
||||
'perPage' => 'nullable|integer|min:1',
|
||||
...DatabaseHelper::getOrderBysValidations(),
|
||||
'search' => DatabaseHelper::getSearchValidation()
|
||||
]);
|
||||
|
||||
$data = ApkUpdate::multiSearch($request->search, ['name'])
|
||||
->multiOrderBy($request->orderBys, 'version_code desc')
|
||||
->paginate($request->perPage ?? 10 );
|
||||
return JSONResponse::Success(['data' => $data]);
|
||||
}
|
||||
|
||||
public function save(Request $request) { return ApkUpdate::upsertFromRequest($request); }
|
||||
public function update(Request $request) { return ApkUpdate::upsertFromRequest($request); }
|
||||
public function delete(Request $request) { return ApkUpdate::deleteFromRequest($request); }
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Tv;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GeneralController extends Controller {
|
||||
public function tvSearch(Request $request) {
|
||||
$request->validate(['search' => 'nullable|string']);
|
||||
$tvs = Tv::multiSearch($request->search, ['code'])->orderBy('code', 'asc')->limit(10)->get();
|
||||
return JSONResponse::Success(['tvs' => $tvs ]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin;
|
||||
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserManagementController extends Controller {
|
||||
public function init(Request $request) {
|
||||
$request->validate([
|
||||
'perPage' => 'nullable|integer|min:1',
|
||||
...DatabaseHelper::getOrderBysValidations(),
|
||||
'search' => DatabaseHelper::getSearchValidation()
|
||||
]);
|
||||
|
||||
$data = User::multiSearch($request->search, ['email', 'username'])
|
||||
->multiOrderBy($request->orderBys, 'created_at desc')
|
||||
->paginate($request->perPage ?? 10 );
|
||||
return JSONResponse::Success(['data' => $data]);
|
||||
}
|
||||
|
||||
public function save(Request $request) { return User::upsertFromRequest($request); }
|
||||
public function update(Request $request) { return User::upsertFromRequest($request); }
|
||||
public function changePassword(Request $request) { return User::changePasswordFromRequest($request); }
|
||||
public function delete(Request $request) { return User::deleteFromRequest($request); }
|
||||
|
||||
public function changeStatus(Request $request) { return User::changeStatusFromRequest($request); }
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin\tv;
|
||||
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\NewTvRequest;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NewTvRequestController extends Controller {
|
||||
public function init(Request $request) {
|
||||
NewTvRequest::deleteExpiredRequests();
|
||||
$request->validate([
|
||||
'perPage' => 'nullable|integer|min:1',
|
||||
...DatabaseHelper::getOrderBysValidations(),
|
||||
'search' => DatabaseHelper::getSearchValidation()
|
||||
]);
|
||||
|
||||
$newTvRequests = NewTvRequest::with('tv')
|
||||
->addColumnCanApprove()
|
||||
->addColumnCanReject()
|
||||
->multiSearch($request->search, ['code'])
|
||||
->multiOrderBy($request->orderBys, 'created_at desc')
|
||||
->paginate($request->perPage ?? 10);
|
||||
|
||||
return JSONResponse::Success(['data' => $newTvRequests ]);
|
||||
}
|
||||
|
||||
public function approve(Request $request) { return NewTvRequest::approveFromRequest($request); }
|
||||
public function reject(Request $request) { return NewTvRequest::rejectFromRequest($request); }
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin\tv;
|
||||
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\Frontend\ApiUtilities;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApkUpdate;
|
||||
use App\Models\Tv;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TvController extends Controller {
|
||||
public function init(Request $request) {
|
||||
$request->validate([
|
||||
'perPage' => 'nullable|integer|min:1',
|
||||
'isFirstTime' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$additionalData = [];
|
||||
if($request->isFirstTime) {
|
||||
$additionalData['apkUpdates'] = ApkUpdate::select('version_code', 'version_name')
|
||||
->orderBy('version_code', 'desc')
|
||||
->get();
|
||||
}
|
||||
$newTvRequests = TV::validateAndGetEloquentFromRequest($request)->paginate($request->perPage ?? 10);
|
||||
return JSONResponse::Success(['data' => $newTvRequests, ...$additionalData ]);
|
||||
}
|
||||
|
||||
public function excel(Request $request) { return ApiUtilities::tvExcel($request); }
|
||||
public function update(Request $request) { return Tv::updateFromRequest($request); }
|
||||
public function changeStatus(Request $request) { return Tv::changeStatusFromRequest($request); }
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class MobileMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response {
|
||||
$serverMobileAuthToken = env('MOBILE_AUTH_TOKEN', '');
|
||||
if(!$serverMobileAuthToken) throw new \Exception('Mobile Auth token in server is not found');
|
||||
|
||||
$clientMobileAuthToken = $request->header('mobile-token', '');
|
||||
if(!$clientMobileAuthToken) $clientMobileAuthToken = $request->header('mobile-auth-token', '');
|
||||
if($serverMobileAuthToken != $clientMobileAuthToken) throw new \Exception('Invalid Mobile Auth Token');
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TvAppInfo extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'tv_app_infos';
|
||||
protected $primaryKey = 'tv_fk';
|
||||
public $incrementing = false;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TvConnectLog extends Model {
|
||||
use HasFactory;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TvSession extends Model {
|
||||
use HasFactory;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Helper\STS\Indokargo;
|
||||
use App\Helper\Traits\Models\CanMultiOrderBy;
|
||||
use App\Helper\Traits\Models\CanMultiSearch;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class NewTvRequest extends Model {
|
||||
use HasFactory;
|
||||
use CanMultiSearch;
|
||||
use CanMultiOrderBy;
|
||||
|
||||
protected $table = 'new_tv_requests';
|
||||
protected $casts = ['device_info'=>AsArrayObject::class];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
// HAS ONE
|
||||
public function self(): HasOne { return $this->hasOne(self::class, 'id', 'id'); }
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO SCOPE
|
||||
public function scopeAddColumnCanApprove(Builder $query) {
|
||||
$query->withCount(['self as can_approve' => function($q) {
|
||||
$q->whereNull('approved_at');
|
||||
}]);
|
||||
}
|
||||
public function scopeAddColumnCanReject(Builder $query) {
|
||||
$query->withCount(['self as can_reject' => function($q) {
|
||||
$q->whereNull('approved_at');
|
||||
}]);
|
||||
}
|
||||
// -- END RELATED TO SCOPE
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO DATA FUNCTION
|
||||
private static function _generateRandomCode(): string {
|
||||
$totalDigit = 6;
|
||||
$randomDigit = '';
|
||||
while(true) {
|
||||
$randomDigit = strtoupper(Str::random($totalDigit));
|
||||
$isExist = NewTvRequest::where('code', $randomDigit)->first();
|
||||
if(!$isExist) break;
|
||||
}
|
||||
return $randomDigit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule:
|
||||
* 1. if it has not been approved for more than the expiry date, deleted it
|
||||
* 2. if it has been approved & has been responded more than expiry date, delete it
|
||||
* - case: when has been approved, but intenet connection missing, how can device know
|
||||
* that the new request tv has been approved?
|
||||
*/
|
||||
private static function _getMaxExpiredTime() :Carbon { return Carbon::now()->subHour(); }
|
||||
public static function deleteExpiredRequests() {
|
||||
$expiredTime = self::_getMaxExpiredTime()->toDateTimeString();
|
||||
NewTvRequest::where(function($q) use ($expiredTime) {
|
||||
$q->whereNull('approved_at')->where('created_at', '<=', $expiredTime);
|
||||
})->orWhere(function($q) use ($expiredTime) {
|
||||
$q->where('responded_at', '<=', $expiredTime );
|
||||
})->delete();
|
||||
}
|
||||
// -- END RELATED TO DATA FUNCTION
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO FROM REQUEST FUNCTION
|
||||
private static function _checkOrCreateResponse(NewTvRequest $newTvReq) {
|
||||
if($newTvReq->approved_at) {
|
||||
// make sure waiting tv_device responded before deleted
|
||||
if(empty($newTvReq->responded_at)) {
|
||||
$newTvReq->responded_at = now();
|
||||
$newTvReq->save();
|
||||
}
|
||||
|
||||
return JSONResponse::Success([
|
||||
'message' => 'approved',
|
||||
'new_tv_request' => $newTvReq,
|
||||
'tv' => $newTvReq->tv
|
||||
]);
|
||||
}
|
||||
|
||||
return JSONResponse::Success([
|
||||
'message' => 'not activate',
|
||||
'new_tv_request' => $newTvReq,
|
||||
'tv' => null
|
||||
]);
|
||||
}
|
||||
public static function checkOrCreateFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
'id' => 'nullable|string|required_with:code|integer',
|
||||
'code' => 'nullable|string|required_with:id',
|
||||
'device_info' => 'required|array'
|
||||
]);
|
||||
|
||||
if(!empty($request->id)) {
|
||||
$checkTvReq = NewTvRequest::where('code', $request->code)->find($request->id);
|
||||
if($checkTvReq) return self::_checkOrCreateResponse($checkTvReq);
|
||||
}
|
||||
|
||||
$newTvReq = new self;
|
||||
$newTvReq->code = self::_generateRandomCode();
|
||||
$newTvReq->device_info = $request->device_info;
|
||||
$newTvReq->save();
|
||||
return self::_checkOrCreateResponse($newTvReq);
|
||||
}
|
||||
|
||||
public static function approveFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
'id' => 'required|integer|exists:App\Models\NewTvRequest',
|
||||
'tv' => 'nullable|array',
|
||||
'existingTv' => 'nullable|array',
|
||||
'action' => 'required|string',
|
||||
]);
|
||||
|
||||
$newTvReq = NewTvRequest::addColumnCanApprove()
|
||||
->findOrFail($request->id);
|
||||
if(!$newTvReq->can_approve) throw new \Exception('Cannot approve current request');
|
||||
|
||||
try {
|
||||
$tv = null;
|
||||
if($request->action == 'existing') {
|
||||
$existingTvRequest = new Request($request->existingTv);
|
||||
$existingTvRequest->validate([
|
||||
'id' => 'required|integer|exists:App\Models\Tv',
|
||||
]);
|
||||
|
||||
$tv = TV::findOrFail($existingTvRequest->id);
|
||||
} else if ($request->action == 'new') {
|
||||
$tvRequest = new Request($request->tv);
|
||||
if($tvRequest->code) $tvRequest->merge(['code' => strtoupper($tvRequest->code)]);
|
||||
|
||||
$tvRequest->validate([
|
||||
'company_name' => 'nullable|string',
|
||||
'address' => 'nullable|string',
|
||||
'street_address' => 'nullable|string',
|
||||
'col1' => 'nullable|string',
|
||||
'col2' => 'nullable|string',
|
||||
'col3' => 'nullable|string',
|
||||
'col4' => 'nullable|string',
|
||||
'col5' => 'nullable|string',
|
||||
'col6' => 'nullable|string',
|
||||
'col7' => 'nullable|string',
|
||||
'col8' => 'nullable|string',
|
||||
'col9' => 'nullable|string',
|
||||
'col10' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
$tv = new Tv();
|
||||
$tv->code = TV::generateUniqueCode();
|
||||
$tv->company_name = $tvRequest->company_name;
|
||||
$tv->address = $tvRequest->address;
|
||||
$tv->street_address = $tvRequest->street_address;
|
||||
$tv->col1 = $tvRequest->col1;
|
||||
$tv->col2 = $tvRequest->col2;
|
||||
$tv->col3 = $tvRequest->col3;
|
||||
$tv->col4 = $tvRequest->col4;
|
||||
$tv->col5 = $tvRequest->col5;
|
||||
$tv->col6 = $tvRequest->col6;
|
||||
$tv->col7 = $tvRequest->col7;
|
||||
$tv->col8 = $tvRequest->col8;
|
||||
$tv->col9 = $tvRequest->col9;
|
||||
$tv->col10 = $tvRequest->col10;
|
||||
$tv->notes = $tvRequest->notes;
|
||||
$tv->device_info = $newTvReq->device_info;
|
||||
$tv->installed_at = now();
|
||||
$tv->save();
|
||||
TvLog::historyCreate($request->user(), $tv->id, $tv);
|
||||
|
||||
// TODO: waiting execution until update from ops
|
||||
// NEED TO REFACTOR (cause by add existing tv code)
|
||||
// // try to sys_to_sys with indokargo
|
||||
// DB::commit();
|
||||
// $jsonResponse = Indokargo::createTVAddress($tvRequest, $tv->id);
|
||||
// return $jsonResponse;
|
||||
} else {
|
||||
throw new \Exception('INVALID FORM ACTION');
|
||||
}
|
||||
|
||||
$newTvReq->approved_at = now();
|
||||
$newTvReq->tv_fk = $tv->id;
|
||||
$newTvReq->save();
|
||||
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message'=>'Success to approve new tv request']);
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
public static function rejectFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
'id' => 'required|integer|exists:App\Models\NewTvRequest',
|
||||
]);
|
||||
$newTvRequest = NewTvRequest::addColumnCanReject()
|
||||
->findOrFail($request->id);
|
||||
if(!$newTvRequest->can_reject) throw new \Exception('Cannot reject current request');
|
||||
$newTvRequest->delete();
|
||||
|
||||
return JSONResponse::Success(['data' => $newTvRequest ]);
|
||||
}
|
||||
// -- END RELATED TO FROM REQUEST FUNCTION
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
|
||||
class Outlet extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'outlets';
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO MIGRATION
|
||||
/// HAS ONE
|
||||
public function tv_app_info(): HasOne { return $this->hasOne(Tv::class, 'outlet_fk', 'id'); }
|
||||
// -- END RELATED TO MIGRATION2
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class StsLog extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'sts_logs';
|
||||
|
||||
protected $fillable = [
|
||||
'partner',
|
||||
'is_outgoing',
|
||||
'module',
|
||||
'service_name',
|
||||
'local_id',
|
||||
'partner_id',
|
||||
'seq',
|
||||
'result',
|
||||
'error_info',
|
||||
'request_data',
|
||||
'request_time',
|
||||
'response_data',
|
||||
'response_time',
|
||||
'is_retry',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
protected $casts = [
|
||||
'error_info' => AsArrayObject::class,
|
||||
'request_data' => AsArrayObject::class,
|
||||
'response_data' => AsArrayObject::class,
|
||||
];
|
||||
|
||||
const STATUS_SUCCESS = 'success';
|
||||
const STATUS_FAILED = 'failed';
|
||||
const STATUS_WARNING = 'warning';
|
||||
|
||||
const PARTNER_INDOKARGO = 'indokargo';
|
||||
|
||||
// related to indokargo
|
||||
const MODULE_TV = 'tv';
|
||||
const SERVICE_CREATE_TV_ADDRESS = 'create-tv-address';
|
||||
const SERVICE_UPDATE_TV_ADDRESS = 'update-tv-address';
|
||||
const SERVICE_CHANGE_STATUS_TV_ADDRESS = 'change-statustv-address';
|
||||
}
|
||||
@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helper\Common;
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Helper\STS\Indokargo;
|
||||
use App\Helper\Traits\Models\CanMultiOrderBy;
|
||||
use App\Helper\Traits\Models\CanMultiSearch;
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class Tv extends Model {
|
||||
use HasFactory;
|
||||
use CanMultiSearch;
|
||||
use CanMultiOrderBy;
|
||||
|
||||
protected $table = 'tvs';
|
||||
protected $hidden = ['ik_cust_id', 'ik_address_id'];
|
||||
protected $casts = ['device_info'=>AsArrayObject::class];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// HAS ONE
|
||||
public function new_tv_request(): HasOne { return $this->hasOne(NewTvRequest::class, 'tv_fk', 'id'); }
|
||||
public function tv_app_info(): HasOne { return $this->hasOne(TvAppInfo::class, 'tv_fk', 'id'); }
|
||||
/// HAS MANY
|
||||
public function tv_connect_logs(): HasMany { return $this->hasMany(TvConnectLog::class, 'tv_fk', 'id'); }
|
||||
public function tv_sessions(): HasMany { return $this->hasMany(TvSession::class, 'tv_fk', 'id'); }
|
||||
/// BELONGS TO
|
||||
public function outlet(): BelongsTo { return $this->belongsTo(Outlet::class, 'outlet_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO DATA FUNCTION
|
||||
public static function generateUniqueCode() {
|
||||
// init
|
||||
$countSuffixDigit = 5;
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
$prefixCode = 'TV' . date('Ym');
|
||||
|
||||
// try to get unique suffix
|
||||
$uniqueCode = '';
|
||||
while(true) {
|
||||
$suffixCode = strtoupper(Str::random($countSuffixDigit));
|
||||
$uniqueCode = $prefixCode . $suffixCode;
|
||||
$isUnique = TV::where('code', $uniqueCode)->first();
|
||||
if(!$isUnique) break;
|
||||
}
|
||||
return $uniqueCode;
|
||||
}
|
||||
// -- END RELATED TO DATA FUNCTION
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO REQUEST
|
||||
public static function validateAndGetEloquentFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
...DatabaseHelper::getOrderBysValidations(),
|
||||
'search' => DatabaseHelper::getSearchValidation(),
|
||||
'apkVersionCode' => 'nullable|integer',
|
||||
'tz' => 'required|timezone',
|
||||
'isActive' => 'nullable|boolean',
|
||||
'installedAt' => 'nullable|array',
|
||||
'installedAt.from' => 'nullable|date',
|
||||
'installedAt.to' => 'nullable|date',
|
||||
'lastConnectedAt' => 'nullable|array',
|
||||
'lastConnectedAt.from' => 'nullable|date',
|
||||
'lastConnectedAt.to' => 'nullable|date',
|
||||
'lastConnectedDay' => 'nullable|int'
|
||||
]);
|
||||
Common::setTimezone($request->tz);
|
||||
|
||||
return Tv::when($request->isActive != null, function($q) use($request) {
|
||||
$q->where('is_active', $request->isActive);
|
||||
})
|
||||
->when($request->apkVersionCode, function($q, $apkVersionCode) {
|
||||
$q->where('apk_version_code', $apkVersionCode);
|
||||
})
|
||||
->when($request->installedAt['from'] ?? '', function($q, $from) {
|
||||
$q->where(DB::raw('DATE(installed_at)'), '>=', $from);
|
||||
})
|
||||
->when($request->installedAt['to'] ?? '', function($q, $to) {
|
||||
$q->where(DB::raw('DATE(installed_at)'), '<=', $to);
|
||||
})
|
||||
->when($request->lastConnectedAt['from'] ?? '', function($q, $from) {
|
||||
$q->where(DB::raw('DATE(last_connected_at)'), '>=', $from);
|
||||
})
|
||||
->when($request->lastConnectedAt['to'] ?? '', function($q, $to) {
|
||||
$q->where(DB::raw('DATE(last_connected_at)'), '<=', $to);
|
||||
})
|
||||
->multiSearch($request->search, ['code', 'company_name'])
|
||||
->multiOrderBy($request->orderBys, 'created_at desc');
|
||||
}
|
||||
|
||||
public static function updateFromRequest(Request $request) {
|
||||
if($request->code) $request->merge(['code' => strtoupper($request->code)]);
|
||||
$request->validate([
|
||||
'id' => 'required|integer|exists:App\Models\Tv',
|
||||
'code' => ['required','string',Rule::unique('tvs', 'code')
|
||||
->when($request->id, function($q, $id) { $q->whereNot('id', $id);})],
|
||||
'company_name' => 'nullable|string',
|
||||
'address' => 'nullable|string',
|
||||
'street_address' => 'nullable|string',
|
||||
'col1' => 'nullable|string',
|
||||
'col2' => 'nullable|string',
|
||||
'col3' => 'nullable|string',
|
||||
'col4' => 'nullable|string',
|
||||
'col5' => 'nullable|string',
|
||||
'col6' => 'nullable|string',
|
||||
'col7' => 'nullable|string',
|
||||
'col8' => 'nullable|string',
|
||||
'col9' => 'nullable|string',
|
||||
'col10' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$tv = TV::findOrFail($request->id);
|
||||
$oldTv = $tv->replicate();
|
||||
$tv->company_name = $request->company_name;
|
||||
$tv->address = $request->address;
|
||||
$tv->street_address = $request->street_address;
|
||||
$tv->code = $request->code;
|
||||
$tv->col1 = $request->col1;
|
||||
$tv->col2 = $request->col2;
|
||||
$tv->col3 = $request->col3;
|
||||
$tv->col4 = $request->col4;
|
||||
$tv->col5 = $request->col5;
|
||||
$tv->col6 = $request->col6;
|
||||
$tv->col7 = $request->col7;
|
||||
$tv->col8 = $request->col8;
|
||||
$tv->col9 = $request->col9;
|
||||
$tv->col10 = $request->col10;
|
||||
$tv->notes = $request->notes;
|
||||
$tv->update();
|
||||
|
||||
TvLog::historyUpdate($request->user(), $tv->id, $oldTv, $tv);
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message'=>'Success to update tv data']);
|
||||
|
||||
// TODO: waiting from ops workflow (Dont forget to resync co_name, address, street address in ik)
|
||||
// // try to sys_to_sys with indokargo
|
||||
// $jsonResponse = Indokargo::updateTVAddress($request, $tv->id, $tv->ik_address_id);
|
||||
// DB::commit();
|
||||
// return $jsonResponse;
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollback();
|
||||
throw $th;
|
||||
}
|
||||
|
||||
}
|
||||
public static function changeStatusFromRequest(Request $request) {
|
||||
$request->validate(['id' => 'required|integer|exists:App\Models\TV,id']);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$tv = Tv::findOrFail($request->id);
|
||||
$tv->is_active = !$tv->is_active;
|
||||
$tv->save();
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message'=>'Success to change tv status']);
|
||||
|
||||
// TODO: waiting from ops workflow (Dont forget to resync co_name, address, street address in ik)
|
||||
// // try to sys_to_sys with indokargo
|
||||
// $jsonResponse = Indokargo::changeStatusAddress(new Request(['is_active' => $tv->is_active]),
|
||||
// $tv->id, $tv->ik_address_id);
|
||||
// DB::commit();
|
||||
// return $jsonResponse;
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
// -- END RELATED TO REQUEST
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO EXCEL
|
||||
public static function getExcelDetail(Request $request) {
|
||||
return JSONResponse::Success(['rows' => TV::validateAndGetEloquentFromRequest($request)->get()]);
|
||||
}
|
||||
|
||||
// ---- RELATED TO EXPORT IMPORT
|
||||
const EXCEL_SUCCESS = 'success';
|
||||
const EXCEL_FAILED = 'failed';
|
||||
const EXCEL_NO_CHANGE = 'no_change';
|
||||
const EXCEL_UPDATE = 'update';
|
||||
const EXCEL_TEMPLATE_COLS = ['code', 'company_name', 'address', 'street_address', 'notes',
|
||||
'col1', 'col2', 'col3', 'col4', 'col5',
|
||||
'col6', 'col7', 'col8', 'col9', 'col10',
|
||||
'is_active'];
|
||||
public static function getExcelTemplate() {
|
||||
$row = [];
|
||||
foreach(self::EXCEL_TEMPLATE_COLS as $col) { $row[$col] = ''; }
|
||||
$rows = [$row];
|
||||
return JSONResponse::Success(['rows' => $rows]);
|
||||
}
|
||||
public static function getExportData(Request $request) {
|
||||
$rows = TV::validateAndGetEloquentFromRequest($request)->get();
|
||||
return JSONResponse::Success(['rows' => $rows, 'cols' => self::EXCEL_TEMPLATE_COLS]);
|
||||
}
|
||||
// ------ RELATED TO IMPORT
|
||||
private static function _checkExcelFormat($tvRows) {
|
||||
if(!$tvRows) throw new \Exception("No Data");
|
||||
|
||||
$firstTvRow = $tvRows[0];
|
||||
if(!$firstTvRow) throw new \Exception('Column not found');
|
||||
|
||||
// check if excel is empty or not
|
||||
$firstTvRow['row'] = null;
|
||||
if(!array_filter($firstTvRow)) throw new \Exception("Excel is empty");
|
||||
|
||||
// check is header col is exists
|
||||
$errors = [];
|
||||
foreach(self::EXCEL_TEMPLATE_COLS as $col) {
|
||||
if(!array_key_exists($col, $firstTvRow)) $errors[$col] = "Column $col is Required";
|
||||
}
|
||||
if($errors) throw ValidationException::withMessages($errors);
|
||||
}
|
||||
private static function _getCountTvCodes($tvRows, $tvCodes) {
|
||||
if(!$tvCodes) $tvCodes = array_column($tvRows, 'code');
|
||||
$tvCodes = array_map(function($code) { return DatabaseHelper::trimUpperNull($code) ?? ''; }, $tvCodes);
|
||||
return array_count_values($tvCodes);
|
||||
}
|
||||
private static function _changeModelFromTvRow(Tv $tv, $tvRow) {
|
||||
$tv->company_name = $tvRow['company_name'];
|
||||
$tv->address = $tvRow['address'];
|
||||
$tv->street_address = $tvRow['street_address'];
|
||||
$tv->code = $tvRow['code'];
|
||||
$tv->col1 = $tvRow['col1'];
|
||||
$tv->col2 = $tvRow['col2'];
|
||||
$tv->col3 = $tvRow['col3'];
|
||||
$tv->col4 = $tvRow['col4'];
|
||||
$tv->col5 = $tvRow['col5'];
|
||||
$tv->col6 = $tvRow['col6'];
|
||||
$tv->col7 = $tvRow['col7'];
|
||||
$tv->col8 = $tvRow['col8'];
|
||||
$tv->col9 = $tvRow['col9'];
|
||||
$tv->col10 = $tvRow['col10'];
|
||||
$tv->notes = $tvRow['notes'];
|
||||
return $tv;
|
||||
}
|
||||
public static function validateExcel($tvRows, $tvCodes = []) {
|
||||
self::_checkExcelFormat($tvRows);
|
||||
$countTvCodes = self::_getCountTvCodes($tvRows, $tvCodes);
|
||||
|
||||
$endStatus = self::EXCEL_SUCCESS;
|
||||
$results = [];
|
||||
foreach($tvRows as $tvRow) {
|
||||
$status = self::EXCEL_NO_CHANGE;
|
||||
$message = '';
|
||||
$tvRow['code'] = strtoupper($tvRow['code'] ?? '');
|
||||
|
||||
try {
|
||||
// STEP 1: check validation
|
||||
$validator = Validator::make($tvRow, [
|
||||
'row' => 'required|integer',
|
||||
'code' => 'required|string',
|
||||
'company_name' => 'nullable|string',
|
||||
'address' => 'nullable|string',
|
||||
'street_address' => 'nullable|string',
|
||||
'col1' => 'nullable|string',
|
||||
'col2' => 'nullable|string',
|
||||
'col3' => 'nullable|string',
|
||||
'col4' => 'nullable|string',
|
||||
'col5' => 'nullable|string',
|
||||
'col6' => 'nullable|string',
|
||||
'col7' => 'nullable|string',
|
||||
'col8' => 'nullable|string',
|
||||
'col9' => 'nullable|string',
|
||||
'col10' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
if($validator->fails()) {
|
||||
$errors = $validator->errors()->toArray();
|
||||
$messages = [];
|
||||
foreach($errors as $eMessages) { $messages = array_merge($messages, $eMessages); }
|
||||
throw new \Exception(implode(', ', $messages));
|
||||
}
|
||||
|
||||
// STEP 2: check code is duplicate or not or not
|
||||
$code = $tvRow['code'];
|
||||
if(($countTvCodes[$code] ?? 0) > 1) throw new \Exception('Code is Duplicate in Excel');
|
||||
|
||||
// STEP 3: check code existing in database or not
|
||||
$tvCheck = Tv::where('code', 'ilike', $code)->first();
|
||||
if(!$tvCheck) throw new \Exception("TV Code '$code' not found in database");
|
||||
|
||||
// STEP 4: check has update data or not
|
||||
$tvCheck = self::_changeModelFromTvRow($tvCheck, $tvRow);
|
||||
if($tvCheck->isDirty()) {
|
||||
$status = self::EXCEL_UPDATE;
|
||||
$message = DatabaseHelper::compileDirtyEloquentToArrMessage($tvCheck);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$endStatus = self::EXCEL_FAILED;
|
||||
$status = self::EXCEL_FAILED;
|
||||
$message = $th->getMessage();
|
||||
}
|
||||
$results[] = ['row' => $tvRow['row'], 'status' => $status, 'message' => $message];
|
||||
}
|
||||
return ['status' => $endStatus, 'results' => $results];
|
||||
}
|
||||
public static function uploadExcel($tvRows, $oValidation, User $user) {
|
||||
$validationResults = $oValidation['results'];
|
||||
$countUploads = [
|
||||
self::EXCEL_UPDATE => 0, self::EXCEL_NO_CHANGE => 0, self::EXCEL_FAILED => 0
|
||||
];
|
||||
$additionalErrors = [];
|
||||
|
||||
foreach($validationResults as $result) {
|
||||
$validateStatus = $result['status'];
|
||||
try {
|
||||
switch($validateStatus) {
|
||||
case self::EXCEL_FAILED:
|
||||
throw new \Exception($result['message']);
|
||||
break;
|
||||
|
||||
case self::EXCEL_UPDATE:
|
||||
// get sparepart data
|
||||
$idxTvRow = array_search($result['row'], array_column($tvRows, 'row'));
|
||||
if($idxTvRow === false) throw new \Exception('Row Not Found');
|
||||
$tvRow = $tvRows[$idxTvRow];
|
||||
$tvRow['code'] = strtoupper($tvRow['code'] ?? '');
|
||||
|
||||
// try to upsert
|
||||
DB::beginTransaction();
|
||||
$tv = TV::where('code', 'ilike', $tvRow['code'])->firstOrFail();
|
||||
$oldTV = $tv->replicate();
|
||||
$newTv = self::_changeModelFromTvRow($tv, $tvRow);
|
||||
if(!$newTv->isDirty()) throw new \Exception('No Change');
|
||||
$newTv->save();
|
||||
|
||||
// save data log
|
||||
TvLog::historyUpdateExcel($user, $newTv->id, $oldTV, $newTv);
|
||||
DB::commit();
|
||||
break;
|
||||
|
||||
case self::EXCEL_NO_CHANGE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollBack();
|
||||
$validateStatus = self::EXCEL_FAILED;
|
||||
$additionalErrors[] = 'row ' . ($result['row'] ?? '-') . ' => ' . $th->getMessage();
|
||||
}
|
||||
|
||||
$countUploads[$validateStatus]++;
|
||||
}
|
||||
|
||||
return ['countUploads' => $countUploads, 'additionalErrors' => $additionalErrors];
|
||||
}
|
||||
// ------ END RELATED TO IMPORT
|
||||
// ---- END RELATED TO EXPORT IMPORT
|
||||
// -- END RELATED TO EXCEL
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TvLog extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'tv_logs';
|
||||
protected $hidden = ['ik_cust_id', 'ik_address_id'];
|
||||
protected $casts = ['from'=>'object', 'to'=>'object'];
|
||||
|
||||
const TYPES = ['create', 'update', 'update-excel'];
|
||||
|
||||
public static function historyCreate(User $user, int $tvFk, Tv $newTv) { self::saveHistory('create', $user, $tvFk, null, $newTv); }
|
||||
public static function historyUpdate(User $user, int $tvFk, Tv $oldTv, Tv $newTv) { self::saveHistory('update', $user, $tvFk, $oldTv, $newTv); }
|
||||
public static function historyUpdateExcel(User $user, int $tvFk, Tv $oldTv, Tv $newTv) { self::saveHistory('update-excel', $user, $tvFk, $oldTv, $newTv); }
|
||||
|
||||
private static function saveHistory(String $type, ?User $user, int $tvFk, ?Tv $oldTv, ?Tv $newTv) {
|
||||
if(!in_array($type, self::TYPES)) throw new \Exception("Type '$type' No Valid");
|
||||
$tvLog = new TvLog();
|
||||
$tvLog->tv_fk = $tvFk;
|
||||
$tvLog->type = $type;
|
||||
if($oldTv) {
|
||||
$oldTv = $oldTv->toArray();
|
||||
unset($oldTv['id']);
|
||||
$tvLog->from =$oldTv;
|
||||
}
|
||||
if($newTv) {
|
||||
$newTv = $newTv->toArray();
|
||||
unset($newTv['id']);
|
||||
$tvLog->to = $newTv;
|
||||
}
|
||||
if($user) { $tvLog->user_fk = $user->id; }
|
||||
$tvLog->save();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
Notes:
|
||||
- Auto Update app
|
||||
- Auto Update video
|
||||
- Laravel Sanctum
|
||||
@ -0,0 +1,2 @@
|
||||
Notes:
|
||||
- TV information & Logs
|
||||
@ -0,0 +1,43 @@
|
||||
<?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('outlets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50)->index();
|
||||
$table->string('name', 255)->nullable()->index();
|
||||
$table->string('address', 255)->nullable();
|
||||
$table->string('street_address', 255)->nullable();
|
||||
$table->string('phone', 50)->nullable()->index();
|
||||
$table->double('lat')->default(0);
|
||||
$table->double('long')->default(0);
|
||||
$table->string('notes', 255)->nullable();
|
||||
$table->string('country', 255);
|
||||
$table->string('ik_country_id', 255);
|
||||
$table->string('state', 255);
|
||||
$table->string('ik_state_id', 255);
|
||||
$table->string('region', 255);
|
||||
$table->string('ik_region_id', 255);
|
||||
$table->string('city', 255);
|
||||
$table->string('ik_city_id', 255);
|
||||
$table->string('zipcode', 255)->nullable();
|
||||
$table->timestampTz('last_visited_at')->nullable();
|
||||
$table->timestampsTz();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::drop('outlets');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,109 @@
|
||||
<?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('tvs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50)->unique();
|
||||
$table->string('ik_address_id', 255)->nullable();
|
||||
$table->integer('apk_version_code')->nullable();
|
||||
$table->string('apk_version_name')->nullable();
|
||||
$table->string('company_name')->nullable();
|
||||
$table->string('address')->nullable();
|
||||
$table->string('street_address')->nullable();
|
||||
$table->string('col1', 255)->nullable();
|
||||
$table->string('col2', 255)->nullable();
|
||||
$table->string('col3', 255)->nullable();
|
||||
$table->string('col4', 255)->nullable();
|
||||
$table->string('col5', 255)->nullable();
|
||||
$table->string('col6', 255)->nullable();
|
||||
$table->string('col7', 255)->nullable();
|
||||
$table->string('col8', 255)->nullable();
|
||||
$table->string('col9', 255)->nullable();
|
||||
$table->string('col10', 255)->nullable();
|
||||
$table->string('notes', 255)->nullable();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->jsonb('device_info')->nullable();
|
||||
$table->timestampTz('installed_at');
|
||||
$table->timestampTz('last_connected_at')->nullable();
|
||||
$table->timestampsTz();
|
||||
});
|
||||
|
||||
Schema::create('new_tv_requests', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50);
|
||||
$table->jsonb('device_info')->nullable();
|
||||
$table->foreignId('tv_fk')->nullable();
|
||||
$table->timestampTz('approved_at')->nullable();
|
||||
$table->timestampTz('responded_at')->nullable();
|
||||
$table->timestampsTz();
|
||||
});
|
||||
|
||||
Schema::create('tv_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('tv_fk');
|
||||
$table->string('type');
|
||||
$table->json('from')->nullable();
|
||||
$table->json('to')->nullable();
|
||||
$table->foreignId('user_fk')->nullable();
|
||||
$table->timestampsTz();
|
||||
|
||||
$table->foreign('tv_fk')->references('id')->on('tvs')->cascadeOnDelete();
|
||||
$table->foreign('user_fk')->references('id')->on('users');
|
||||
});
|
||||
|
||||
// Schema::create('tv_sessions', function (Blueprint $table) {
|
||||
// $table->id();
|
||||
// $table->foreignId('tv_fk')->index();
|
||||
// $table->timestampTz('started_at')->index();
|
||||
// $table->timestampTz('finished_at')->nullable()->index();
|
||||
// $table->boolean('is_playing_video');
|
||||
// $table->jsonb('current_videos')->nullable();
|
||||
// $table->timestampsTz();
|
||||
|
||||
// $table->foreign('tv_fk')->references('id')->on('tvs');
|
||||
// });
|
||||
|
||||
// Schema::create('tv_app_infos', function (Blueprint $table) {
|
||||
// $table->foreignId('tv_fk')->unique()->index();
|
||||
// $table->timestampTz('installed_at')->nullable()->index();
|
||||
// $table->jsonb('current_videos')->nullable();
|
||||
// $table->timestampTz('last_updated_video')->nullable()->index();
|
||||
// $table->timestampsTz();
|
||||
|
||||
// $table->foreign('tv_fk')->references('id')->on('tvs');
|
||||
// });
|
||||
|
||||
// Schema::create('tv_app_logs', function (Blueprint $table) {
|
||||
// $table->id();
|
||||
// $table->foreignId('tv_fk')->index();
|
||||
// $table->string('requested_to');
|
||||
// $table->string('ip', 50);
|
||||
// $table->jsonb('request_data')->nullable();
|
||||
// $table->enum('result', ['success', 'failed']);
|
||||
// $table->jsonb('response_data')->nullable();
|
||||
// $table->timestampsTz();
|
||||
|
||||
// $table->foreign('tv_fk')->references('id')->on('tvs');
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
// Schema::drop('tv_app_logs');
|
||||
// Schema::drop('tv_app_infos');
|
||||
// Schema::drop('tv_sessions');
|
||||
Schema::drop('tv_logs');
|
||||
Schema::drop('new_tv_requests');
|
||||
Schema::drop('tvs');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
<?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('sts_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('partner', 255)->nullable();
|
||||
$table->boolean('is_outgoing');
|
||||
$table->string('module', 255)->nullable();
|
||||
$table->string('service_name', 255)->nullable();
|
||||
$table->string('local_id', 255)->nullable();
|
||||
$table->string('partner_id', 255)->nullable();
|
||||
$table->enum('result', ['success', 'failed', 'warning']);
|
||||
$table->jsonb('error_info')->nullable();
|
||||
$table->tinyInteger('seq');
|
||||
$table->jsonb('request_data')->nullable();
|
||||
$table->timestampTz('request_time')->nullable();
|
||||
$table->jsonb('response_data')->nullable();
|
||||
$table->timestampTz('response_time')->nullable();
|
||||
$table->boolean('is_retry')->default('false');
|
||||
$table->timestampsTz();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::drop('sts_logs');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,26 @@
|
||||
<?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('video_updates', function(Blueprint $table) {
|
||||
$table->double('file_size_kb')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::table('video_updates', function(Blueprint $table) {
|
||||
$table->dropColumn('file_size_kb');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -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('apk_updates', function (Blueprint $table) {
|
||||
$table->string('version_name', 50)->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('apk_updates', function (Blueprint $table) {
|
||||
$table->dropColumn('version_name');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\api\mobile\CheckUpdateController;
|
||||
use App\Http\Controllers\api\mobile\TvController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::controller(CheckUpdateController::class)->group(function() {
|
||||
Route::post('/check-update/video-update/latest', 'videoUpdateLatest');
|
||||
Route::post('/check-update/apk-update/latest', 'apkUpdateLatest');
|
||||
});
|
||||
|
||||
Route::controller(TvController::class)->group(function() {
|
||||
Route::post('/tv/new-request', 'newRequest');
|
||||
Route::post('/tv/check-update', 'checkUpdate');
|
||||
});
|
||||
?>
|
||||
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\api\superadmin\ApkUploadController;
|
||||
use App\Http\Controllers\api\superadmin\GeneralController;
|
||||
use App\Http\Controllers\api\superadmin\tv\NewTvRequestController;
|
||||
use App\Http\Controllers\api\superadmin\tv\TvController;
|
||||
use App\Http\Controllers\api\superadmin\UserManagementController;
|
||||
use App\Http\Controllers\api\superadmin\VideoUploadController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::controller(GeneralController::class)->group(function() {
|
||||
Route::post('/general/tv/search', 'tvSearch');
|
||||
});
|
||||
|
||||
Route::controller(VideoUploadController::class)->group(function() {
|
||||
Route::post('/video-upload', 'init');
|
||||
Route::post('/video-upload/save', 'save');
|
||||
Route::post('/video-upload/update', 'update');
|
||||
Route::post('/video-upload/delete', 'delete');
|
||||
Route::post('/video-upload/change-selected-video', 'changeSelectedVideo');
|
||||
});
|
||||
|
||||
Route::controller(ApkUploadController::class)->group(function() {
|
||||
Route::post('/apk-upload', 'init');
|
||||
Route::post('/apk-upload/save', 'save');
|
||||
Route::post('/apk-upload/update', 'update');
|
||||
Route::post('/apk-upload/delete', 'delete');
|
||||
});
|
||||
|
||||
Route::controller(UserManagementController::class)->group(function() {
|
||||
Route::post('/user-management', 'init');
|
||||
Route::post('/user-management/save', 'save');
|
||||
Route::post('/user-management/update', 'update');
|
||||
Route::post('/user-management/change-password', 'changePassword');
|
||||
Route::post('/user-management/change-status', 'changeStatus');
|
||||
Route::post('/user-management/delete', 'delete');
|
||||
});
|
||||
|
||||
Route::controller(TvController::class)->group(function() {
|
||||
Route::post('/tv/tv', 'init');
|
||||
Route::post('/tv/tv/update', 'update');
|
||||
Route::post('/tv/tv/change-status', 'changeStatus');
|
||||
Route::post('/tv/tv/excel', 'excel');
|
||||
});
|
||||
|
||||
Route::controller(NewTvRequestController::class)->group(function() {
|
||||
Route::post('/tv/new-tv-request', 'init');
|
||||
Route::post('/tv/new-tv-request/approve', 'approve');
|
||||
Route::post('/tv/new-tv-request/reject', 'reject');
|
||||
Route::post('/tv/new-tv-request/tv/search', 'tvSearch');
|
||||
});
|
||||
?>
|
||||
Loading…
Reference in New Issue