This commit is contained in:
Naden
2026-04-25 04:41:23 +07:00
commit 7e9668a552
195 changed files with 20254 additions and 0 deletions

0
app/Libraries/.gitkeep Normal file
View File

View File

@@ -0,0 +1,50 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
/**
* @property Broadcast $broadcast
*/
const SEND_GROUP = "T2vGHuNWqwUQFtk2D96xt9Hkq8dyHEXVwBXPMz8_oaA";
const SEND_INSTAN = "T2vGHuNWqwUQFtk2D96xt3hwktFc4t7cTiz74HCwOaM";
class Broadcast extends ProdevMessagesAbstract
{
/** @param array{ daftar_group: string, daftar_pesan_id: string } $data */
public function sendGroup(string $daftar_group, string $daftar_pesan_id): array
{
$form = [
'daftar_group' => $daftar_group,
'daftar_pesan_id' => $daftar_pesan_id
];
$response = $this->client->request(
'POST',
SEND_GROUP,
[
'form_params' => $this->getform($form)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function sendInstan(array $data): array
{
$response = $this->client->request(
'POST',
SEND_INSTAN,
[
'form_params' => $this->getform($data)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
/**
* @property Group $multiple
*/
const GET_ALL = "4YsZVeivKQDHNbC9QapHxA";
const INSERT = "ucdyZBMN9J7hivfx1AQIeg";
const UPDATE = "H9w1hTiHDGgiINLIVCgqOg/";
class Group extends ProdevMessagesAbstract
{
public function getAll()
{
$response = $this->client->request(
'POST',
GET_ALL,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body);
}
}
/** @param array{ nama_group: string, isi_pesan: string } $data */
public function insert(string $nama_group, string $isi_pesan = '')
{
$form = [
'nama_group' => $nama_group,
'isi_pesan' => $isi_pesan
];
$response = $this->client->request(
'POST',
INSERT,
[
'form_params' => $this->getform($form)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function update(string $nama_group, string $daftar_group_id): array
{
$form = [
'nama_group' => $nama_group,
];
$response = $this->client->request(
'POST',
UPDATE . $daftar_group_id,
[
'form_params' => $this->getform($form)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body);
}
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
/**
* @property ListMessage $listmessage
*/
const GET_ALL = "380XyFK0cI_hY_wHrP4SjA";
const INSERT = "jn2GXQvR98hGPHIDqgqN8g";
const UPDATE = "sS9omGVprCLnzt1lq-7QQw/";
const SHOW_PESAN_BY_PESAN_ID = "RkL2559LgadI185K5-IthjCqvZSBEhWUEOj1AaxD6so/";
const DELETE = "F5y8aFIoVgS8zx5hmiVPEw/";
class ListMessage extends ProdevMessagesAbstract
{
public function getAll(): array
{
$response = $this->client->request(
'POST',
GET_ALL,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function insert(string $daftar_pesan_isi, string $judul_pesan): array
{
$form = $this->getform(
[
'daftar_pesan_isi' => $daftar_pesan_isi,
'judul_pesan' => $judul_pesan
]
);
$response = $this->client->request(
'POST',
INSERT,
[
'form_params' => $this->getform($form)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function update(string $daftar_pesan_isi, string $judul_pesan, string $daftar_pesan_id): array
{
$form = $this->getform(
[
'daftar_pesan_isi' => $daftar_pesan_isi,
'judul_pesan' => $judul_pesan
]
);
$response = $this->client->request(
'POST',
UPDATE . $daftar_pesan_id,
[
'form_params' => $this->getform($form)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function showByid(string $daftar_pesan_id): array
{
$response = $this->client->request(
'POST',
SHOW_PESAN_BY_PESAN_ID . $daftar_pesan_id,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function delete(string $daftar_pesan_id): array
{
$response = $this->client->request(
'POST',
DELETE . $daftar_pesan_id,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
/**
* @property Multiple $multiple
*/
class Multiple extends ProdevMessagesAbstract
{
public function sendText(string $username, string $password): array
{
$response = $this->client->request('POST', '/api/v2/send-message', [
'form_params' => [
'username' => $username,
'password' => $password,
'date' => $this->getMillisecond(),
],
]);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return (array)$body;
} else {
return $this->errorCode($body['errcode']);
}
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
// const URL = "http://localhost/adhivasindo/wa-api/index.php/RMuumzsQWg5HtzQb/";
const URL = "https://blast.awh.co.id/index.php/RMuumzsQWg5HtzQb/";
/**
* @property Group $group
* @property Multiple $multiple
* @property ListMessage $listmessage
* @property Broadcast $broadcast
* @property UserList $userlist
*/
class ProdevMessages
{
/**
* @var string
*/
private $ProdevToken = '';
/**
* @var \GuzzleHttp\Client
*/
private $client;
public function __construct(string $ProdevToken)
{
$headers = [
'Content-Type' => 'application/x-www-form-urlencoded'
];
$this->ProdevToken = $ProdevToken;
$this->client = new \GuzzleHttp\Client(
[
'base_uri' => URL,
'headers' => $headers,
],
);
}
protected $container = [];
protected $providers = [
"multiple" => Multiple::class,
"group" => Group::class,
"listmessage" => ListMessage::class,
"broadcast" => Broadcast::class,
"userlist" => UserList::class,
];
/**
* @param $name
* @return mixed
* @throws \Exception
*/
public function __get($name)
{
if (!isset($this->providers[$name])) {
throw new \Exception("class not found");
} else {
if (!isset($this->container[$name]) || !$this->container[$name] instanceof ProdevMessagesAbstract) {
try {
$this->container["{$name}"] = new $this->providers[$name]($this->ProdevToken, $this->client);
} catch (\Exception $e) {
throw new $e;
}
}
return $this->container["{$name}"];
}
}
static function getDateTimeMillisecond(string $dateTime): int
{
$dateTime = $dateTime . ".0";
list($usec, $sec) = explode(".", $dateTime);
$date = strtotime($usec);
$return_data = str_pad($date . $sec, 13, "0", STR_PAD_RIGHT);
return (int)$return_data;
}
/**
* @param string $dateTime
* @return int
*/
}

View File

@@ -0,0 +1,122 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
/**
* @property Group $group
* @property Multiple $multiple
*/
const error_code =
[
/**
* Account Error Code
*/
1 => "proses gagal",
10000 => "invalid client_id",
10001 => "invalid client",
10003 => "invalid token",
10004 => "invalid access",
10007 => "username atau password salah",
10011 => "invalid refresh token",
20002 => "not lock admin",
30002 => "invalid username, hanya huruf latin yang diperbolehkan",
30003 => "user sudah ada",
30004 => "invalid userid to delete",
30005 => "password harus md5 encrypted",
30006 => "exceeds the restrictions of API call number",
80000 => "date harus waktu sekarang, dalam 5 menit",
80002 => "invalid json format",
90000 => "internal server error",
-3 => "invalid parameter",
-2018 => "permission denied",
-4063 => "Please delete/transfer all yours locks first",
/**
* Lock Error Code
*/
-1003 => "lock tidak ada",
-2025 => "lock frozen, tidak bisa dioperasikan",
-3011 => "Cannot Transfer Lock(s) to Yourself",
-4043 => "The function is not supported for this lock",
-4056 => "run out of memory",
-4067 => "NB Device tidak terdaftar",
-4082 => "waktu auto locking tidak sah",
/**
* Gateway Error Code
*/
-2012 => "Lock tidak terhubung ke gateway manapun",
-3002 => "The gateway is offline. Please check and try again.",
-3003 => "gateway sibuk, coba lagi",
-3016 => "Cannot Transfer Gateway(s) to Yourself.",
-3034 => "Network not configed. Please config the network and try again.",
-3035 => "Wifi lock is in power saving mode, please turn off power saving and try again",
-3036 => "The lock is offline. Please check and try again",
-3037 => "The lock is busy. Please try again later",
-4037 => "No such Gateway exists",
/**
* RFID / IC Card Error Code
*/
-1021 => "This IC Card does not exist",
-1023 => "This Fingerprint does not exist",
/**
* Passcode Error Code
*/
-1007 => "No password data of this lock",
-2009 => "Invalid Password",
-3006 => "Invalid Passcode. Passcode should be between 6 - 9 Digits in length",
-3007 => "The same passcode already exists. Please use another one",
-3008 => "A Passcode that has never been used on the Lock cannot be changed",
-3009 => "There is NO SPACE to store Customized Passcodes. Please Delete Un-Used Customized Passcodes and try again",
];
/**
* Class BaseAbstract
*/
abstract class ProdevMessagesAbstract
{
/**
* @var string
*/
protected $ProdevToken = '';
/**
* @var \GuzzleHttp\Client
*/
protected $client;
final function __construct(string $ProdevToken, \GuzzleHttp\Client $client)
{
$this->ProdevToken = $ProdevToken;
$this->client = $client;
}
protected function getMillisecond()
{
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
}
protected static function errorCode(int $code)
{
$data = [
'code' => $code,
'message' => error_code[$code]
];
return $data;
}
static function queryBuildier($get)
{
(string)$string = '';
foreach ($get as $key => $value) {
$string .= $key . '=' . $value . '&';
}
return substr_replace($string, "", -1);
}
function getform($form = [])
{
$option = [
'AccessToken' => $this->ProdevToken
];
if ($form) {
foreach ($form as $v => $d) {
$option[$v] = $d;
}
}
return $option;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace ArelAyudhi\Prodev;
/**
* @property QrPayment $QrPayment
*/
const URL = "https://api.xendit.co/";
class ProdevXendit
{
/**
* @var string
*/
private $ProdevToken = '';
/**
* @var \GuzzleHttp\Client
*/
private $client;
public function __construct($xendit_key)
{
$headers = [
'Content-Type' => 'application/json',
'api-version' => ' 2022-07-31',
];
$this->client = new \GuzzleHttp\Client(
[
'base_uri' => URL,
'headers' => $headers,
'auth' => [$xendit_key, ''],
],
);
}
protected $container = [];
protected $providers = [
"QrPayment" => QrPayment::class,
"VirtualAccount" => VirtualAccount::class,
];
/**
* @param $name
* @return mixed
* @throws \Exception
*/
public function __get($name)
{
if (!isset($this->providers[$name])) {
throw new \Exception("class not found");
} else {
if (!isset($this->container[$name]) || !$this->container[$name] instanceof ProdevXenditAbstract) {
try {
$this->container["{$name}"] = new $this->providers[$name]($this->client);
} catch (\Exception $e) {
throw new $e;
}
}
return $this->container["{$name}"];
}
}
static function getDateTimeMillisecond(string $dateTime): int
{
$dateTime = $dateTime . ".0";
list($usec, $sec) = explode(".", $dateTime);
$date = strtotime($usec);
$return_data = str_pad($date . $sec, 13, "0", STR_PAD_RIGHT);
return (int)$return_data;
}
/**
* @param string $dateTime
* @return int
*/
}

View File

@@ -0,0 +1,121 @@
<?php
namespace ArelAyudhi\Prodev;
/**
* @property Group $group
* @property Multiple $multiple
*/
const error_code =
[
/**
* Account Error Code
*/
1 => "proses gagal",
10000 => "invalid client_id",
10001 => "invalid client",
10003 => "invalid token",
10004 => "invalid access",
10007 => "username atau password salah",
10011 => "invalid refresh token",
20002 => "not lock admin",
30002 => "invalid username, hanya huruf latin yang diperbolehkan",
30003 => "user sudah ada",
30004 => "invalid userid to delete",
30005 => "password harus md5 encrypted",
30006 => "exceeds the restrictions of API call number",
80000 => "date harus waktu sekarang, dalam 5 menit",
80002 => "invalid json format",
90000 => "internal server error",
-3 => "invalid parameter",
-2018 => "permission denied",
-4063 => "Please delete/transfer all yours locks first",
/**
* Lock Error Code
*/
-1003 => "lock tidak ada",
-2025 => "lock frozen, tidak bisa dioperasikan",
-3011 => "Cannot Transfer Lock(s) to Yourself",
-4043 => "The function is not supported for this lock",
-4056 => "run out of memory",
-4067 => "NB Device tidak terdaftar",
-4082 => "waktu auto locking tidak sah",
/**
* Gateway Error Code
*/
-2012 => "Lock tidak terhubung ke gateway manapun",
-3002 => "The gateway is offline. Please check and try again.",
-3003 => "gateway sibuk, coba lagi",
-3016 => "Cannot Transfer Gateway(s) to Yourself.",
-3034 => "Network not configed. Please config the network and try again.",
-3035 => "Wifi lock is in power saving mode, please turn off power saving and try again",
-3036 => "The lock is offline. Please check and try again",
-3037 => "The lock is busy. Please try again later",
-4037 => "No such Gateway exists",
/**
* RFID / IC Card Error Code
*/
-1021 => "This IC Card does not exist",
-1023 => "This Fingerprint does not exist",
/**
* Passcode Error Code
*/
-1007 => "No password data of this lock",
-2009 => "Invalid Password",
-3006 => "Invalid Passcode. Passcode should be between 6 - 9 Digits in length",
-3007 => "The same passcode already exists. Please use another one",
-3008 => "A Passcode that has never been used on the Lock cannot be changed",
-3009 => "There is NO SPACE to store Customized Passcodes. Please Delete Un-Used Customized Passcodes and try again",
];
/**
* Class BaseAbstract
*/
abstract class ProdevXenditAbstract
{
/**
* @var string
*/
protected $ProdevToken = '';
/**
* @var \GuzzleHttp\Client
*/
protected $client;
final function __construct(\GuzzleHttp\Client $client)
{
$this->client = $client;
}
protected function getMillisecond()
{
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
}
protected static function errorCode(int $code)
{
$data = [
'code' => $code,
'message' => error_code[$code]
];
return $data;
}
static function queryBuildier($get)
{
(string)$string = '';
foreach ($get as $key => $value) {
$string .= $key . '=' . $value . '&';
}
return substr_replace($string, "", -1);
}
function getform($form = [])
{
$option = [
'AccessToken' => $this->ProdevToken
];
if ($form) {
foreach ($form as $v => $d) {
$option[$v] = $d;
}
}
return $option;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace ArelAyudhi\Prodev;
/**
* @property QrPayment $QrPayment
*/
const CREATE_QR = "qr_codes";
const CHECK_QR = "qr_codes/";
class QrPayment extends ProdevXenditAbstract
{
/** @param array{ nama_penerima[0]: string, nomor_penerima[0]: string, nomor_penerima[0]: string } $data */
public function create_qr(array $data): array
{
// print_r($this->client);die;
$response = $this->client->request(
'POST',
CREATE_QR,
[
'body' => json_encode($data)
]
);
$body = json_decode($response->getBody()->getContents(), true);
return $body;
}
public function check_qr(string $data): array
{
$response = $this->client->request(
'GET',
CHECK_QR . $data,
);
$body = json_decode($response->getBody()->getContents(), true);
return $body;
}
}

View File

@@ -0,0 +1,161 @@
<?php
namespace ArelAyudhi\DhivaProdevWa;
/**
* @property UserList $userlist
*/
const USER_LIST_GET_ALL = "eXvZjC3J1L3eNrqTEfc8mQ";
const USER_LIST_ALL_BY_GROUP_ID = "O7skdKVrEKhNkzkJm2WjaQms5SWijPt7b7yclfXwFvrTksqxEylS7tZC-Yff4RsW/";
const USER_LIST_ALL_BY_NAMA = "O7skdKVrEKhNkzkJm2WjaYhTwxA7MOeaqdT04OR6P0o/";
const USER_LIST_ALL_BY_NOMOR_TELEPON = "O7skdKVrEKhNkzkJm2WjaZ4hncBYJmRW5G5UynOx7JXLKLtvEhDJI4Ql2wG5mB--/";
const USER_LIST_SHOW_BY_NAMA_ID = "o3O-xMLw9O65qs2ibXvUkXPd5nqGKyYF39S_Y3LVuaQoPq4rsejLJPHi93ha_ilo/";
const USER_LIST_INSERT = "omj4wqnUSftatKfOYM5jyFcmIBSCJuwm3XQAR-jeTVw";
const USER_LIST_UPDATE = "mcJ9dTuItmpxsD5CuSswKgVqCDFIj2sLeqvY_JkCNQw/";
const GET_ALL = "eXvZjC3J1L3eNrqTEfc8mQ";
const USER_LIST_DELETE = "ucenwGz_ed9qVf6QxFxExZb1nnBvKxdxdbAiDZUdup4/";
class UserList extends ProdevMessagesAbstract
{
public function getAll(): array
{
$response = $this->client->request(
'POST',
GET_ALL,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function allByGroupId(string $group_penerima): array
{
$response = $this->client->request(
'POST',
USER_LIST_ALL_BY_GROUP_ID . $group_penerima,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function allByNama(string $nama_penerima): array
{
$response = $this->client->request(
'POST',
USER_LIST_ALL_BY_NAMA . $nama_penerima,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function allByNomorTelepon(string $nomor_penerima): array
{
$response = $this->client->request(
'POST',
USER_LIST_ALL_BY_NOMOR_TELEPON . $nomor_penerima,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function showByNamaId(string $daftar_penerima_id): array
{
$response = $this->client->request(
'POST',
USER_LIST_SHOW_BY_NAMA_ID . $daftar_penerima_id,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
/** @param array{ nama_penerima[0]: string, nomor_penerima[0]: string, nomor_penerima[0]: string } $data */
public function insert(array $data): array
{
$response = $this->client->request(
'POST',
USER_LIST_INSERT,
[
'form_params' => $this->getform($data)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function update(string $nama_penerima = '', int $nomor_penerima, string $group_penerima = '', string $daftar_penerima_id): array
{
$form = [];
if ($nama_penerima) {
$form['nama_penerima'] = $nama_penerima;
}
if ($nomor_penerima) {
$form['nomor_penerima'] = $nomor_penerima;
}
if ($group_penerima) {
$form['group_penerima'] = $group_penerima;
}
$response = $this->client->request(
'POST',
USER_LIST_UPDATE . $daftar_penerima_id,
[
'form_params' => $this->getform($form)
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
public function delete(string $daftar_penerima_id): array
{
$response = $this->client->request(
'POST',
USER_LIST_DELETE . $daftar_penerima_id,
[
'form_params' => $this->getform()
]
);
$body = json_decode($response->getBody()->getContents(), true);
if ($response->getStatusCode() === 200) {
return $body;
} else {
return $this->errorCode($body['errcode']);
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace ArelAyudhi\Prodev;
/**
* @property VirtualAccount $VirtualAccount
*/
const CREATE_VA = "callback_virtual_accounts";
const CHECK_VA = "callback_virtual_accounts/";
class VirtualAccount extends ProdevXenditAbstract
{
/** @param array{ nama_penerima[0]: string, nomor_penerima[0]: string, nomor_penerima[0]: string } $data */
public function create_va(array $data): array
{
// print_r($this->client);die;
$response = $this->client->request(
'POST',
CREATE_VA,
[
'body' => json_encode($data)
]
);
$body = json_decode($response->getBody()->getContents(), true);
return $body;
}
public function check_va(string $data): array
{
$response = $this->client->request(
'GET',
CHECK_VA . $data,
);
$body = json_decode($response->getBody()->getContents(), true);
return $body;
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "arelayudhi/dhiva-prodev-wa",
"description": "Dhiva WA",
"minimum-stability": "stable",
"prefer-stable": true,
"autoload": {
"psr-4": {
"ArelAyudhi\\DhivaProdevWa\\": "src/"
}
}
}

111
app/Libraries/DhivaAES.php Normal file
View File

@@ -0,0 +1,111 @@
<?php
namespace Dhiva\Core;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class DhivaAES
{
public static function base64url_encode($data, $password = false)
{
return rtrim(strtr(base64_encode(openssl_encrypt($data, "AES-256-CBC", self::keypair($password), OPENSSL_RAW_DATA, SSL_KEY['iv'])), '+/', '-_'), '=');
}
public static function base64url_decode($data, $password = false)
{
$decrypt = openssl_decrypt(base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)), "AES-256-CBC", self::keypair($password), OPENSSL_RAW_DATA, SSL_KEY['iv']);
return $decrypt;
}
private static function keypair($password)
{
$data = ($password == false) ? SSL_KEY['password'] : $password;
return openssl_pbkdf2($data, SSL_KEY['salt'], SSL_KEY['keyLength'], SSL_KEY['iterations'], "sha256");
}
public static function randomString($aes = false)
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for ($i = 0; $i < 10; $i++) {
$index = rand(0, strlen($characters) - 1);
$randomString .= $characters[$index];
}
return $randomString;
}
public static function jwtencode($token)
{
$tokenParts = explode(".", $token);
$tokenPayload = self::base64url_encode($tokenParts[1]);
return $tokenPayload;
}
public static function jwtdecode($private, $public)
{
$tokenParts = explode(".", $public);
$tokenHeader = $tokenParts[0];
$tokenPayload = self::base64url_decode($private);
if (isset($tokenParts[2])) {
$tokenSignature = $tokenParts[2];
$data = $tokenHeader . "." . $tokenPayload . "." . $tokenSignature;
} else {
return ERROR_TOKEN_UNIDENTIFIED;
}
return $data;
}
public static function jwtvalidator($private, $public)
{
$tokenPrivate = self::jwtdecode($private, $public);
$match = ($tokenPrivate === $public) ? true : false;
return $match;
}
/**
* Generator String dengan enkripsi
*
* @param mixed $length
* @param mixed $aes
* @return string
*/
public static function randomStr(int $length, $aes = false): string
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$index = rand(0, strlen($characters) - 1);
$randomString .= $characters[$index];
}
if ($aes) {
$randomString = self::base64url_encode(strval(intval(microtime(true) * 1000)), 5);
}
return $randomString;
}
public static function aesencodeid(string $string, int $length)
{
$tokenPayload = self::base64url_encode($string . self::randomStr($length));
return $tokenPayload;
}
public static function validateTimestampWtihUserAccess($tokens)
{
$token = self::validateToken($tokens);
if ($token == false) {
return ERROR_TOKEN_UNIDENTIFIED;
}
$model = model('App\Models\SqlModel\SuperUserModelSql');
$user = $model->showBy('super_user_id', $token->super_user_id);
$lastTimeStamp = strtotime($user->access_at);
$timeStampTimeOut = ($lastTimeStamp + JWT_TIMEOUT) - now();
if ($timeStampTimeOut < 0 || !$user->token || $token->token != $user->token) {
$update = ['token' => null];
// $model->update($update, $token->super_user_id);
// return ERROR_TOKEN_EXPIRED;
}
return $token;
}
public static function validateToken($token)
{
return JWT::decode($token, new Key(JWT_KEY, 'HS256'));
}
public static function generateToken($data)
{
return JWT::encode($data, JWT_KEY, 'HS256');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Controllers;
/**
* Model Load
* $this->model->{{tabel}};
*/
class {{controller}}Controller extends BaseController
{
protected $table = '{{tabel}}';
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Config;
use CodeIgniter\Database\Config;
/**
* Database Configuration
*/
class Database extends Config
{
/**
* The directory that holds the Migrations
* and Seeds directories.
*/
public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
/**
* Lets you choose which connection group to
* use if no other is specified.
*/
public string $defaultGroup = 'default';
/**
* The default database connection for mysql.
*/
public array $default = [
'DSN' => '',
'hostname' => 'localhost',
'username' => '{{username}}',
'password' => '{{password}}',
'database' => '{{tabel}}',
'DBDriver' => '{{DBDriver}}',
'schema' => '{{schema}}',
'DBPrefix' => '',
'pConnect' => false,
'DBDebug' => true,
'charset' => 'utf8',
'DBCollat' => 'utf8_bin',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'numberNative' => false,
];
/**
* This database connection is used when
* running PHPUnit database tests.
*/
public array $tests = [
'DSN' => '',
'hostname' => '127.0.0.1',
'username' => '',
'password' => '',
'database' => ':memory:',
'DBDriver' => 'SQLite3',
'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
'pConnect' => false,
'DBDebug' => true,
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306,
'foreignKeys' => true,
'busyTimeout' => 1000,
];
public function __construct()
{
parent::__construct();
// Ensure that we always set the database group to 'tests' if
// we are currently running an automated test suite, so that
// we don't overwrite live data on accident.
if (ENVIRONMENT === 'testing') {
$this->defaultGroup = 'tests';
}
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace App\Models\SqlModel;
class {{model}}ModelSql extends BaseModelSql
{
protected $table = '{{tabel}}';
}

View File

@@ -0,0 +1 @@
DhivaRoutes::Route($routes, '{{routes}}', '{{controller}}Controller');

View File

@@ -0,0 +1,143 @@
#--------------------------------------------------------------------
# Example Environment Configuration file
#
# This file can be used as a starting point for your own
# custom .env files, and contains most of the possible settings
# available in a default install.
#
# By default, all of the settings are commented out. If you want
# to override the setting, you must un-comment it by removing the '#'
# at the beginning of the line.
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = production
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
# app.baseURL = ''
# If you have trouble with `.`, you could also use `_`.
# app_baseURL = ''
# app.forceGlobalSecureRequests = false
# app.CSPEnabled = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
# database.default.hostname = localhost
# database.default.database = ci4
# database.default.username = root
# database.default.password = root
# database.default.DBDriver = MySQLi
# database.default.DBPrefix =
# database.default.port = 3306
# database.tests.hostname = localhost
# database.tests.database = ci4_test
# database.tests.username = root
# database.tests.password = root
# database.tests.DBDriver = MySQLi
# database.tests.DBPrefix =
# database.tests.port = 3306
#--------------------------------------------------------------------
# CONTENT SECURITY POLICY
#--------------------------------------------------------------------
# contentsecuritypolicy.reportOnly = false
# contentsecuritypolicy.defaultSrc = 'none'
# contentsecuritypolicy.scriptSrc = 'self'
# contentsecuritypolicy.styleSrc = 'self'
# contentsecuritypolicy.imageSrc = 'self'
# contentsecuritypolicy.baseURI = null
# contentsecuritypolicy.childSrc = null
# contentsecuritypolicy.connectSrc = 'self'
# contentsecuritypolicy.fontSrc = null
# contentsecuritypolicy.formAction = null
# contentsecuritypolicy.frameAncestors = null
# contentsecuritypolicy.frameSrc = null
# contentsecuritypolicy.mediaSrc = null
# contentsecuritypolicy.objectSrc = null
# contentsecuritypolicy.pluginTypes = null
# contentsecuritypolicy.reportURI = null
# contentsecuritypolicy.sandbox = false
# contentsecuritypolicy.upgradeInsecureRequests = false
# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}'
# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}'
# contentsecuritypolicy.autoNonce = true
#--------------------------------------------------------------------
# COOKIE
#--------------------------------------------------------------------
# cookie.prefix = ''
# cookie.expires = 0
# cookie.path = '/'
# cookie.domain = ''
# cookie.secure = false
# cookie.httponly = false
# cookie.samesite = 'Lax'
# cookie.raw = false
#--------------------------------------------------------------------
# ENCRYPTION
#--------------------------------------------------------------------
# encryption.key =
# encryption.driver = OpenSSL
# encryption.blockSize = 16
# encryption.digest = SHA512
#--------------------------------------------------------------------
# HONEYPOT
#--------------------------------------------------------------------
# honeypot.hidden = 'true'
# honeypot.label = 'Fill This Field'
# honeypot.name = 'honeypot'
# honeypot.template = '<label>{label}</label><input type="text" name="{name}" value=""/>'
# honeypot.container = '<div style="display:none">{template}</div>'
#--------------------------------------------------------------------
# SECURITY
#--------------------------------------------------------------------
# security.csrfProtection = 'cookie'
# security.tokenRandomize = false
# security.tokenName = 'csrf_token_name'
# security.headerName = 'X-CSRF-TOKEN'
# security.cookieName = 'csrf_cookie_name'
# security.expires = 7200
# security.regenerate = true
# security.redirect = false
# security.samesite = 'Lax'
#--------------------------------------------------------------------
# SESSION
#--------------------------------------------------------------------
# session.driver = 'CodeIgniter\Session\Handlers\FileHandler'
# session.cookieName = 'ci_session'
# session.expiration = 7200
# session.savePath = null
# session.matchIP = false
# session.timeToUpdate = 300
# session.regenerateDestroy = false
#--------------------------------------------------------------------
# LOGGER
#--------------------------------------------------------------------
# logger.threshold = 4
#--------------------------------------------------------------------
# CURLRequest
#--------------------------------------------------------------------
# curlrequest.shareOptions = true

View File

@@ -0,0 +1,45 @@
<?php
namespace Dhiva\Core;
use CodeIgniter\Router\RouteCollection as BaseRouteCollection;
class DhivaRoutes extends BaseRouteCollection
{
static function Route($routes, $path, $controller)
{
if (isset($_SERVER['REQUEST_METHOD'])) {
$routes->post('endpoencode', 'EndpointController::encodeEndpoint');
$routes->post('endpodecode', 'EndpointController::checkEncodeEndpoint');
$routes->get('image/(:segment)', 'AssetsController::decodeImage/$1');
$routes->get('pdf/(:segment)', 'AssetsController::decodePdf/$1');
$routes->post(SSL_KEY['route'] . '/(:segment)', 'RoutesController::decodeEndpointPost/$1');
$routes->get(SSL_KEY['route'] . '/(:segment)', 'RoutesController::decodeEndpointGet/$1');
$routes->put(SSL_KEY['route'] . '/(:segment)', 'RoutesController::decodeEndpointPut/$1');
$routes->delete(SSL_KEY['route'] . '/(:segment)', 'RoutesController::decodeEndpointDelete/$1');
$routes->post(SSL_KEY['route'] . '/(:segment)/(:segment)', 'RoutesController::decodeEndpointPost/$1/$2');
$routes->get(SSL_KEY['route'] . '/(:segment)/(:segment)', 'RoutesController::decodeEndpointGet/$1/$2');
$routes->put(SSL_KEY['route'] . '/(:segment)/(:segment)', 'RoutesController::decodeEndpointPut/$1/$2');
$routes->delete(SSL_KEY['route'] . '/(:segment)/(:segment)', 'RoutesController::decodeEndpointDelete/$1/$2');
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
$routes->get($path, $controller . "::index");
$routes->get($path . '/(:segment)', $controller . '::showAll/$1');
$routes->get($path . '/pages/(:segment)/(:segment)', $controller . '::pagination/$1/$2');
$routes->get($path . '/pagesbydate/(:segment)/(:segment)/(:segment)/(:segment)', $controller . '::paginationByDate/$1/$2/$3/$4');
$routes->get($path . '/show_by/(:segment)/(:segment)', $controller . '::showBy/$1/$2');
$routes->get($path . '/all_by/(:segment)/(:segment)', $controller . '::allBy/$1/$2');
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$routes->post($path, $controller . "::create");
$routes->post($path . '/all-by', $controller . '::allByPost');
$routes->post($path . '/show-by', $controller . '::showByPost');
$routes->post($path . '/update/(:segment)', $controller . '::update/$1');
$routes->post($path . '/pagination', $controller . '::paginationpost');
} else if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
$routes->delete($path . '/delete/(:segment)', $controller . '::destroy/$1');
}
}
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Libraries;
use CodeIgniter\Config\Services;
use Throwable;
class DistribusiService
{
public function __construct()
{
}
}

View File

@@ -0,0 +1,423 @@
<?php
namespace App\Libraries;
use CodeIgniter\Config\Services;
class EmailService
{
protected $email;
public function __construct()
{
$emailConfig = new \Config\Email();
$this->email = Services::email($emailConfig);
}
/**
* Kirim OTP via Email
*
* @param string $toEmail Email tujuan
* @param string $otpCode Kode OTP
* @param string $userName Nama user
* @param string $pangkat Pangkat user
* @return array ['success' => bool, 'message' => string]
*/
public function sendOtpEmail($toEmail, $otpCode, $userName, $pangkat = '')
{
try {
$this->email->setFrom('prodevbackend587@gmail.com', 'E-Teguran Humanis Polda NTB');
$this->email->setTo($toEmail);
$this->email->setSubject('E-Teguran Humanis - Verifikasi OTP');
$message = $this->getOtpEmailTemplate($otpCode, $userName, $pangkat);
$this->email->setMessage($message);
$result = $this->email->send();
if ($result) {
// PATCH: Set SMTPConnect ke null agar tidak error di __destruct
$reflection = new \ReflectionProperty($this->email, 'SMTPConnect');
$reflection->setAccessible(true);
$reflection->setValue($this->email, null);
// Cleanup
$this->email->clear(true);
return [
'success' => true,
'message' => 'Email OTP berhasil dikirim'
];
} else {
log_message('error', 'Email send error: ' . $this->email->printDebugger(['headers']));
// PATCH: Set SMTPConnect ke null agar tidak error di __destruct
$reflection = new \ReflectionProperty($this->email, 'SMTPConnect');
$reflection->setAccessible(true);
$reflection->setValue($this->email, null);
// Cleanup
$this->email->clear(true);
return [
'success' => false,
'message' => 'Gagal mengirim email OTP'
];
}
} catch (\Exception $e) {
log_message('error', 'Email exception: ' . $e->getMessage());
// PATCH: Set SMTPConnect ke null agar tidak error di __destruct
try {
$reflection = new \ReflectionProperty($this->email, 'SMTPConnect');
$reflection->setAccessible(true);
$reflection->setValue($this->email, null);
$this->email->clear(true);
} catch (\Exception $cleanupEx) {
// Ignore cleanup errors
}
return [
'success' => false,
'message' => 'Terjadi kesalahan saat mengirim email: ' . $e->getMessage()
];
}
}
/**
* Template HTML untuk email OTP (sesuai desain aplikasi)
*/
private function getOtpEmailTemplate($otpCode, $userName, $pangkat = '')
{
$fullName = !empty($pangkat) ? "{$pangkat} {$userName}" : $userName;
return '<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>E-Teguran Humanis Polda NTB</title>
<!-- Gmail-Compatible Email Styling -->
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, Helvetica, sans-serif !important;
color: #374151 !important;
background-color: #f0f9ff !important;
line-height: 1.6 !important;
margin: 0 !important;
padding: 0 !important;
}
table {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
.email-wrapper {
width: 100% !important;
background-color: #f0f9ff !important;
padding: 20px 0 !important;
}
.email-container {
width: 600px !important;
max-width: 600px !important;
margin: 0 auto !important;
background-color: #ffffff !important;
border-radius: 12px !important;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.email-header {
background-color: #002A95 !important;
color: #ffffff !important;
padding: 30px 20px !important;
text-align: center !important;
}
.logo-container {
margin-bottom: 20px !important;
text-align: center !important;
}
.logo-container img {
width: 80px !important;
height: 80px !important;
border-radius: 50% !important;
background-color: #ffffff !important;
padding: 2px !important;
display: inline-block !important;
vertical-align: middle !important;
border: 1px solid rgba(255, 255, 255, 0.3) !important;
}
.email-header h1 {
font-size: 24px !important;
font-weight: bold !important;
margin: 15px 0 8px 0 !important;
color: #ffffff !important;
}
.email-header p {
font-size: 14px !important;
color: #ffffff !important;
opacity: 0.9;
margin: 0 !important;
}
.email-body {
padding: 30px 20px !important;
}
.welcome-message {
background-color: #f0f9ff !important;
border-left: 4px solid #002A95 !important;
padding: 20px !important;
border-radius: 6px !important;
margin-bottom: 25px !important;
}
.welcome-message h2 {
color: #0c4a6e !important;
font-size: 18px !important;
font-weight: bold !important;
margin-bottom: 10px !important;
}
.welcome-message p {
color: #075985 !important;
font-size: 14px !important;
line-height: 1.5 !important;
margin: 0 !important;
}
.credentials-container {
background-color: #ffffff !important;
border: 2px solid #e0f2fe !important;
border-radius: 8px !important;
padding: 25px 20px !important;
margin: 25px 0 !important;
text-align: center !important;
}
.credentials-title {
color: #0c4a6e !important;
font-size: 16px !important;
font-weight: bold !important;
margin-bottom: 20px !important;
text-align: center !important;
}
.otp-display {
background-color: #f8fafc !important;
border: 2px dashed #002A95 !important;
border-radius: 8px !important;
padding: 25px !important;
margin: 20px 0 !important;
text-align: center !important;
}
.otp-label {
font-weight: bold !important;
color: #475569 !important;
font-size: 12px !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
margin-bottom: 15px !important;
}
.otp-code {
font-weight: bold !important;
color: #ffffff !important;
font-size: 32px !important;
background-color: #002A95 !important;
padding: 15px 25px !important;
border-radius: 6px !important;
letter-spacing: 8px !important;
display: inline-block !important;
font-family: "Courier New", Courier, monospace !important;
}
.otp-validity {
color: #64748b !important;
font-size: 13px !important;
margin-top: 15px !important;
font-style: italic !important;
}
.security-notice {
background-color: #fef3c7 !important;
border-left: 4px solid #f59e0b !important;
padding: 18px !important;
border-radius: 6px !important;
margin: 25px 0 !important;
}
.security-notice h3 {
color: #92400e !important;
font-size: 14px !important;
font-weight: bold !important;
margin-bottom: 8px !important;
}
.security-notice ul {
margin: 10px 0 0 0 !important;
padding-left: 20px !important;
}
.security-notice li {
color: #b45309 !important;
font-size: 13px !important;
line-height: 1.6 !important;
margin-bottom: 5px !important;
}
.email-footer {
background-color: #1e293b !important;
color: #ffffff !important;
padding: 25px 20px !important;
text-align: center !important;
}
.footer-content {
max-width: 400px;
margin: 0 auto !important;
}
.footer-logo {
font-size: 16px !important;
font-weight: bold !important;
margin-bottom: 8px !important;
color: #ffffff !important;
}
.footer-address {
font-size: 12px !important;
color: #ffffff !important;
opacity: 0.8;
line-height: 1.4 !important;
margin-bottom: 15px !important;
}
.footer-divider {
width: 40px !important;
height: 2px !important;
background-color: #002A95 !important;
margin: 0 auto 15px auto !important;
}
.footer-note {
font-size: 11px !important;
color: #ffffff !important;
opacity: 0.7;
font-style: italic !important;
margin: 0 !important;
}
/* Mobile Responsive */
@media only screen and (max-width: 600px) {
.email-container {
width: 100% !important;
margin: 0 10px !important;
}
.email-header,
.email-body,
.email-footer {
padding: 20px 15px !important;
}
.email-header h1 {
font-size: 20px !important;
}
.credentials-container {
padding: 20px 15px !important;
}
.otp-code {
font-size: 28px !important;
padding: 12px 20px !important;
letter-spacing: 6px !important;
}
}
</style>
</head>
<body>
<div class="email-wrapper">
<table class="email-container" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>
<!-- Header Section -->
<div class="email-header">
<div class="logo-container">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Lambang_Polda_NTB.png/800px-Lambang_Polda_NTB.png"
alt="Logo Polri" style="width: 80px; height: 80px; border-radius: 50%; background-color: #ffffff; padding: 2px; display: inline-block; border: 1px solid rgba(255, 255, 255, 0.3);" />
</div>
<h1>E-Teguran Humanis</h1>
<p>Polda Nusa Tenggara Barat</p>
</div>
<!-- Body Section -->
<div class="email-body">
<div class="welcome-message">
<h2>Verifikasi Akun Anda</h2>
<p>Kepada Yth. <strong>' . htmlspecialchars($fullName) . '</strong>, kami telah menerima permintaan verifikasi akun Anda.</p>
</div>
<div class="credentials-container">
<h3 class="credentials-title">Kode Verifikasi OTP Anda</h3>
<div class="otp-display">
<div class="otp-label">Kode OTP</div>
<div class="otp-code">' . htmlspecialchars($otpCode) . '</div>
<div class="otp-validity">Kode ini berlaku selama 10 menit</div>
</div>
</div>
<div class="security-notice">
<h3>⚠️ Penting untuk Keamanan</h3>
<ul>
<li><strong>Jangan bagikan</strong> kode ini kepada siapa pun</li>
<li>Kode ini hanya berlaku untuk <strong>10 menit</strong></li>
<li>Jika Anda tidak melakukan permintaan ini, segera hubungi administrator sistem</li>
</ul>
</div>
</div>
<!-- Footer Section -->
<div class="email-footer">
<div class="footer-content">
<div class="footer-logo">E-Teguran Humanis</div>
<div class="footer-address">
Polda Nusa Tenggara Barat<br>
Jl. Langko No. 77, Taman Sari, Ampenan, Kota Mataram
</div>
<div class="footer-divider"></div>
<div class="footer-note">
Email ini dikirim secara otomatis, mohon tidak membalas email ini.
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
</body>
</html>';
}
}

View File

@@ -0,0 +1,461 @@
<?php
namespace App\Libraries;
use App\Config\ExternalApi;
class MekariWhatsAppService
{
private $hmacUsername;
private $hmacSecret;
private $apiUrl;
private $channelIntegrationId;
private $messageTemplateId;
private $messageTemplateIdPelanggaranID;
private $messageTemplateIdPelanggaranEN;
private $uploadApiUrl;
public function __construct()
{
$config = config('ExternalApi');
$this->hmacUsername = $config->hmacUsername;
$this->hmacSecret = $config->hmacSecret;
$this->channelIntegrationId = $config->channelIntegrationId;
$this->messageTemplateId = $config->messageTemplateId;
$this->messageTemplateIdPelanggaranID = $config->messageTemplateIdPelanggaranID;
$this->messageTemplateIdPelanggaranEN = $config->messageTemplateIdPelanggaranEN;
$this->apiUrl = 'https://api.mekari.com/qontak/chat/v1/broadcasts/whatsapp/direct';
$this->uploadApiUrl = 'https://api.mekari.com/qontak/chat/v1/file_uploader';
}
/**
* Upload foto ke Mekari untuk digunakan di WhatsApp template
* Jika file WebP, akan dikonversi ke JPEG dulu
*/
public function uploadImage($filePath)
{
$tempJpegPath = null;
try {
if (!file_exists($filePath)) {
throw new \Exception("File tidak ditemukan: {$filePath}");
}
$fileExtension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
$uploadFilePath = $filePath;
$uploadFileName = basename($filePath);
// Konversi WebP ke JPEG
if ($fileExtension === 'webp') {
log_message('debug', "Converting WebP to JPEG: {$filePath}");
$tempJpegPath = sys_get_temp_dir() . '/' . uniqid('wa_upload_') . '.jpg';
$image = imagecreatefromwebp($filePath);
if (!$image) {
throw new \Exception("Gagal membaca file WebP");
}
$converted = imagejpeg($image, $tempJpegPath, 90);
imagedestroy($image);
if (!$converted) {
throw new \Exception("Gagal konversi WebP ke JPEG");
}
$uploadFilePath = $tempJpegPath;
$uploadFileName = pathinfo($filePath, PATHINFO_FILENAME) . '.jpg';
log_message('debug', "WebP converted to JPEG: {$tempJpegPath}");
}
$urlParts = parse_url($this->uploadApiUrl);
$path = $urlParts['path'];
$dateString = gmdate('D, d M Y H:i:s') . ' GMT';
$hmacAuth = $this->generateHmacAuth('POST', $path, $dateString);
$cFile = new \CURLFile($uploadFilePath, 'image/jpeg', $uploadFileName);
$ch = curl_init($this->uploadApiUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: ' . $hmacAuth,
'Date: ' . $dateString
],
CURLOPT_POSTFIELDS => ['file' => $cFile],
CURLOPT_TIMEOUT => 60,
CURLOPT_SSL_VERIFYPEER => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
// Cleanup temporary file
if ($tempJpegPath && file_exists($tempJpegPath)) {
unlink($tempJpegPath);
log_message('debug', "Temporary JPEG file deleted: {$tempJpegPath}");
}
if ($error) {
log_message('error', "Mekari Upload cURL Error: {$error}");
return [
'success' => false,
'message' => 'Gagal upload gambar ke server'
];
}
log_message('debug', "Mekari Upload Response [{$httpCode}]: {$response}");
$result = json_decode($response, true);
if ($httpCode >= 200 && $httpCode < 300 && isset($result['data']['url'])) {
return [
'success' => true,
'message' => 'Gambar berhasil diupload',
'url' => $result['data']['url'],
'filename' => $result['data']['filename']
];
}
$errorMessage = 'Gagal upload gambar';
if (isset($result['error']['message'])) {
$errorMessage = $result['error']['message'];
} elseif (isset($result['message'])) {
$errorMessage = $result['message'];
}
return [
'success' => false,
'message' => $errorMessage
];
} catch (\Exception $e) {
if ($tempJpegPath && file_exists($tempJpegPath)) {
unlink($tempJpegPath);
}
log_message('error', "Mekari Upload Exception: " . $e->getMessage());
return [
'success' => false,
'message' => 'Terjadi kesalahan saat upload gambar: ' . $e->getMessage()
];
}
}
public function sendOtp($phoneNumber, $otpCode, $userName = '', $subject = 'VERIFIKASI AKUN')
{
try {
$phoneNumber = $this->formatPhoneNumber($phoneNumber);
$urlParts = parse_url($this->apiUrl);
$path = $urlParts['path'];
$dateString = gmdate('D, d M Y H:i:s') . ' GMT';
$hmacAuth = $this->generateHmacAuth('POST', $path, $dateString);
$payload = [
'to_number' => $phoneNumber,
'to_name' => $userName ?: 'User',
'message_template_id' => $this->messageTemplateId,
'channel_integration_id' => $this->channelIntegrationId,
'language' => [
'code' => 'id'
],
'parameters' => [
'body' => [
[
'key' => '1',
'value' => 'code',
'value_text' => $otpCode
],
],
"buttons" => [
[
"index" => "0",
"type" => "url",
"value" => "$otpCode"
]
]
]
];
log_message('debug', "Mekari WA OTP Request - Date: {$dateString}");
log_message('debug', "Mekari WA OTP Payload: " . json_encode($payload));
return $this->sendRequest($payload, $hmacAuth, $dateString);
} catch (\Exception $e) {
log_message('error', "Mekari WA OTP Exception: " . $e->getMessage());
return [
'success' => false,
'message' => 'Terjadi kesalahan saat mengirim OTP'
];
}
}
/**
* Kirim notifikasi pelanggaran via WhatsApp dengan header image
*
* @param string $phoneNumber Nomor WhatsApp tujuan
* @param array $data Data pelanggaran dengan keys:
* - nama, jenis_pelanggaran, tanggal_formatted, waktu_formatted
* - lokasi_kejadian, dasar_hukum, pasal, hukuman, urutan_pelanggaran
* - pelanggaran_id, is_luar_negeri, image_url (optional), image_filename (optional)
*/
public function sendNotifikasiPelanggaran($phoneNumber, $data)
{
try {
$phoneNumber = $this->formatPhoneNumber($phoneNumber);
$urlParts = parse_url($this->apiUrl);
$path = $urlParts['path'];
$dateString = gmdate('D, d M Y H:i:s') . ' GMT';
$hmacAuth = $this->generateHmacAuth('POST', $path, $dateString);
$isLuarNegeri = $data['is_luar_negeri'] ?? false;
// $templateId = $isLuarNegeri ?
// $this->messageTemplateIdPelanggaranEN :
// $this->messageTemplateIdPelanggaranID;
$templateId = $this->messageTemplateIdPelanggaranID;
// Validasi required fields
$requiredFields = [
'nama', 'jenis_pelanggaran', 'tanggal_formatted',
'waktu_formatted', 'lokasi_kejadian', 'dasar_hukum',
'pasal', 'hukuman', 'urutan_pelanggaran', 'pelanggaran_id'
];
foreach ($requiredFields as $field) {
if (empty($data[$field])) {
throw new \Exception("Field '{$field}' is required");
}
}
// Kalau template inggris sudah ada bisa di uncomment di bawah ini
// Build body parameters
// if ($isLuarNegeri) {
// $bodyParams = [
// ['key' => '1', 'value' => 'p1', 'value_text' => $data['urutan_pelanggaran']],
// ['key' => '2', 'value' => 'p2', 'value_text' => $data['title'] ?? 'Mr./Ms.'],
// ['key' => '3', 'value' => 'p3', 'value_text' => $data['nama']],
// ['key' => '4', 'value' => 'p4', 'value_text' => $data['jenis_pelanggaran']],
// ['key' => '5', 'value' => 'p5', 'value_text' => $data['tanggal_formatted']],
// ['key' => '6', 'value' => 'p6', 'value_text' => $data['waktu_formatted']],
// ['key' => '7', 'value' => 'p7', 'value_text' => $data['lokasi_kejadian']],
// ['key' => '8', 'value' => 'p8', 'value_text' => $data['dasar_hukum']],
// ['key' => '9', 'value' => 'p9', 'value_text' => $data['pasal']],
// ['key' => '10', 'value' => 'p10', 'value_text' => $data['hukuman']]
// ];
// } else {
// $bodyParams = [
// ['key' => '1', 'value' => 'p1', 'value_text' => $data['urutan_pelanggaran']],
// ['key' => '2', 'value' => 'p2', 'value_text' => $data['nama']],
// ['key' => '3', 'value' => 'p3', 'value_text' => $data['jenis_pelanggaran']],
// ['key' => '4', 'value' => 'p4', 'value_text' => $data['tanggal_formatted']],
// ['key' => '5', 'value' => 'p5', 'value_text' => $data['waktu_formatted']],
// ['key' => '6', 'value' => 'p6', 'value_text' => $data['lokasi_kejadian']],
// ['key' => '7', 'value' => 'p7', 'value_text' => $data['dasar_hukum']],
// ['key' => '8', 'value' => 'p8', 'value_text' => $data['pasal']],
// ['key' => '9', 'value' => 'p9', 'value_text' => $data['hukuman']]
// ];
// }
// Selalu pakai format Indonesia dulu (9 parameter)
$bodyParams = [
['key' => '1', 'value' => 'p1', 'value_text' => $data['urutan_pelanggaran']],
['key' => '2', 'value' => 'p2', 'value_text' => $data['nama']],
['key' => '3', 'value' => 'p3', 'value_text' => $data['jenis_pelanggaran']],
['key' => '4', 'value' => 'p4', 'value_text' => $data['tanggal_formatted']],
['key' => '5', 'value' => 'p5', 'value_text' => $data['waktu_formatted']],
['key' => '6', 'value' => 'p6', 'value_text' => $data['lokasi_kejadian']],
['key' => '7', 'value' => 'p7', 'value_text' => $data['dasar_hukum']],
['key' => '8', 'value' => 'p8', 'value_text' => $data['pasal']],
['key' => '9', 'value' => 'p9', 'value_text' => $data['hukuman']]
];
// Build payload parameters
$parameters = [
'body' => $bodyParams,
'buttons' => [
[
'index' => '0',
'type' => 'url',
'value' => $data['pelanggaran_id']
]
]
];
// Tambahkan header
if (!empty($data['image_url']) && !empty($data['image_filename'])) {
$parameters['header'] = [
'format' => 'IMAGE',
'params' => [
[
'key' => 'url',
'value' => $data['image_url']
],
[
'key' => 'filename',
'value' => $data['image_filename']
]
]
];
} else {
$parameters['header'] = [
'format' => 'IMAGE',
'params' => [
[
'key' => 'url',
'value' => "https://cdn.qontak.com/uploads/direct/images/1ed10e3c-461f-477f-a74a-ee6553f23f4d/photo_2025-11-10_15-32-37.jpg"
],
[
'key' => 'filename',
'value' => "photo_2025-11-10_15-32-37.jpg"
]
]
];
}
$payload = [
'to_number' => $phoneNumber,
'to_name' => $data['nama'],
'message_template_id' => $templateId,
'channel_integration_id' => $this->channelIntegrationId,
'language' => [
'code' => $isLuarNegeri ? 'en' : 'id'
],
'parameters' => $parameters
];
log_message('debug', "Mekari WA Pelanggaran Request - Date: {$dateString}");
log_message('debug', "Mekari WA Pelanggaran Payload: " . json_encode($payload));
$result = $this->sendRequest($payload, $hmacAuth, $dateString);
if ($result['success']) {
log_message('info', "WhatsApp notification sent to {$phoneNumber} for pelanggaran {$data['pelanggaran_id']}");
}
return $result;
} catch (\Exception $e) {
log_message('error', "Mekari WA Pelanggaran Exception: " . $e->getMessage());
return [
'success' => false,
'message' => 'Terjadi kesalahan saat mengirim notifikasi pelanggaran: ' . $e->getMessage()
];
}
}
private function sendRequest($payload, $hmacAuth, $dateString)
{
$ch = curl_init($this->apiUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: ' . $hmacAuth,
'Date: ' . $dateString,
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
log_message('error', "Mekari WA cURL Error: {$error}");
return [
'success' => false,
'message' => 'Gagal terhubung ke server WhatsApp'
];
}
log_message('debug', "Mekari WA Response [{$httpCode}]: {$response}");
$result = json_decode($response, true);
if ($httpCode >= 200 && $httpCode < 300) {
return [
'success' => true,
'message' => 'Pesan berhasil dikirim',
'data' => $result
];
}
$errorMessage = 'Gagal mengirim pesan';
if (isset($result['error']['message'])) {
$errorMessage = $result['error']['message'];
} elseif (isset($result['message'])) {
$errorMessage = $result['message'];
}
log_message('error', "Mekari WA Error [{$httpCode}]: " . $response);
return [
'success' => false,
'message' => $errorMessage,
'error_code' => $result['error']['code'] ?? $httpCode,
// 'raw_response' => $result // Untuk debugging
];
}
private function generateHmacAuth($method, $path, $dateString)
{
$requestLine = strtoupper($method) . ' ' . $path . ' HTTP/1.1';
$stringToSign = 'date: ' . $dateString . "\n" . $requestLine;
$signature = base64_encode(hash_hmac('sha256', $stringToSign, $this->hmacSecret, true));
$hmacHeader = sprintf(
'hmac username="%s", algorithm="hmac-sha256", headers="date request-line", signature="%s"',
$this->hmacUsername,
$signature
);
return $hmacHeader;
}
private function formatPhoneNumber($phone)
{
$phone = preg_replace('/[^0-9]/', '', $phone);
if (substr($phone, 0, 2) === '62') {
return $phone;
}
if (substr($phone, 0, 1) === '0') {
return '62' . substr($phone, 1);
}
return '62' . $phone;
}
public function verifyWebhookSignature($authHeader, $dateHeader, $method, $path)
{
try {
preg_match('/signature="([^"]+)"/', $authHeader, $matches);
$receivedSignature = $matches[1] ?? '';
if (empty($receivedSignature)) {
return false;
}
$requestLine = strtoupper($method) . ' ' . $path . ' HTTP/1.1';
$stringToSign = 'date: ' . $dateHeader . "\n" . $requestLine;
$expectedSignature = base64_encode(hash_hmac('sha256', $stringToSign, $this->hmacSecret, true));
return hash_equals($expectedSignature, $receivedSignature);
} catch (\Exception $e) {
log_message('error', "HMAC Verification Error: " . $e->getMessage());
return false;
}
}
}

1002
app/Libraries/MongoLib.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
<?php
namespace Dhiva\Core;
class Notification
{
public function getNotification()
{
$notification = array();
$notification['title'] = "KAMTIBMAS (KEAMANAN KETERTIBAN MASYARAKAT)";
$notification['message'] = "Selamat datang di Aplikasi KAMTIBMAS (KEAMANAN KETERTIBAN MASYARAKAT) (0)";
$notification['image'] = "https://project.adhivasindo.co.id/diy/assets/logo/logo_polda_diy.png";
return $notification;
}
public function publish($publish)
{
$ff = explode('#', $publish['isi']);
$notification['title'] = $ff[0];
$notification['message'] =$ff[1]. PHP_EOL. $ff[2]. PHP_EOL. $ff[3];
$fields = array('to' => FIREBASE_TOPIC . $publish['topic'], 'data' => $notification);
$url = 'https://fcm.googleapis.com/fcm/send';
$headers = array('Authorization: key=' . FIREBASE_API, 'Content-Type: application/json');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$output = curl_exec($ch);
if (!json_decode($output)) {
print_r($output);
die;
}
curl_close($ch);
return json_decode($output);
}
}

126
app/Libraries/Tenancy.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
namespace Dhiva\Core;
class Tenancy
{
public static function createTenancy($res)
{
self::dbtenancy($res);
}
public static function connectTenancy($res)
{
$db = \Config\Database::forge();
$db = new \Config\Database;
$dbSelect = $db->postgre;
$dbSelect['schema'] = $res;
return \Config\Database::forge($dbSelect);
}
public static function disconnectTenancy()
{
$db = \Config\Database::forge();
$db = new \Config\Database;
$dbSelect = $db->postgre;
$dbSelect['schema'] = 'public';
return \Config\Database::forge($dbSelect);
}
private static function dbtenancy($res)
{
$db = \Config\Database::connect();
$schemaName = '"' . $res . '"';
$query = $db->query('CREATE SCHEMA ' . $schemaName);
if (!$query) {
return 'Gagal membuat ' . $schemaName;
}
$db = new \Config\Database;
$dbSelect = $db->postgre;
$dbSelect['schema'] = $schemaName;
$forge = \Config\Database::forge($dbSelect);
// $forge->addField([
// 'endpoint_id' => [
// 'type' => 'INT',
// 'constraint' => 255,
// 'auto_increment' => true,
// 'unique' => true,
// ],
// 'value' => [
// 'type' => 'VARCHAR',
// 'constraint' => 200,
// ],
// 'description' => [
// 'type' => 'VARCHAR',
// 'constraint' => 200,
// 'null' => true,
// ],
// 'created_by' => [
// 'type' => 'VARCHAR',
// 'constraint' => 200,
// 'null' => true,
// ],
// 'created_at timestamp without time zone NULL DEFAULT CURRENT_TIMESTAMP',
// ]);
// $forge->addKey('endpoint_id', true);
// $forge->createTable('endpoint');
$forge->addField([
'super_user_id' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'super_group_id' => [
'type' => 'TEXT',
'null' => true,
],
'name' => [
'type' => 'VARCHAR',
'constraint' => 50,
'null' => true,
],
'email' => [
'type' => 'VARCHAR',
'constraint' => 50,
'null' => true,
],
'username' => [
'type' => 'VARCHAR',
'constraint' => 50,
'null' => true,
],
'password' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'avatar' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'status' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'token' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'login_date' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'access_at' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'is_admin' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'unit_id' => [
'type' => 'VARCHAR',
'constraint' => 200,
],
'created_at timestamp without time zone NULL DEFAULT CURRENT_TIMESTAMP',
]);
$forge->addKey('super_user_id', true);
$forge->createTable('super_user');
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace App\Libraries;
use CodeIgniter\HTTP\CURLRequest;
class WablasService
{
protected string $token;
protected string $secretKey;
protected string $baseUrl = 'https://tegal.wablas.com/api/v2';
protected $externalApi;
public function __construct()
{
$this->externalApi = new \Config\ExternalApi();
$this->token = env('WABLAS_TOKEN') ?: $this->externalApi->wablasToken;
$this->secretKey = env('WABLAS_SECRET_KEY') ?: $this->externalApi->WablasSecretKey;
if (empty($this->token) || empty($this->secretKey)) {
throw new \Exception('Unauthorized');
}
}
// Kirim pesan teks biasa (single)
public function sendText(string $phone, string $message, bool $isGroup = false): array
{
return $this->sendBulkText([['phone' => $phone, 'message' => $message, 'isGroup' => $isGroup ? 'true' : 'false']]);
}
// Kirim pesan teks massal (multiple)
public function sendBulkText(array $messages): array
{
$formatted = [];
foreach ($messages as $msg) {
if (!isset($msg['phone']) || !isset($msg['message'])) {
throw new \InvalidArgumentException('Setiap pesan harus memiliki "phone" dan "message"');
}
$formatted[] = [
'phone' => $this->sanitizePhone($msg['phone']),
'message' => $msg['message'],
'isGroup' => $msg['isGroup'] ?? 'false'
];
}
return $this->makeRequest('/send-message', ['data' => $formatted]);
}
// Kirim OTP atau template message
public function sendTemplate(string $phone, string $content, string $title = 'Verification Code', string $footer = 'Supported by Wablas', string $code = ''): array
{
$message = [
'title' => [
'type' => 'text',
'content' => $title
],
'content' => $content,
'footer' => $footer
];
// Hanya tambahkan buttons jika code ada
if (!empty($code)) {
$message['buttons'] = [
'url' => [
'display' => 'Copy',
'link' => "https://www.whatsapp.com/otp/copy/" . $code
]
];
}
$payload = [
'data' => [
[
'phone' => $this->sanitizePhone($phone),
'message' => $message
]
]
];
return $this->makeRequest('/send-template', $payload);
}
// Kirim OTP sederhana - PERSIS SEPERTI DOKUMENTASI
public function sendOTP(string $phone, string $code, string $title = 'Verification Code'): array
{
$phone = $this->sanitizePhone($phone);
$message = [
'title' => [
'type' => 'text',
'content' => $title,
],
'buttons' => [
'url' => [
'display' => 'Copy',
'link' => "https://www.whatsapp.com/otp/copy/" . $code,
],
],
'content' => "Your verification code : $code",
'footer' => 'Supported by Wablas',
];
$payload = [
'data' => [
[
'phone' => $phone,
'message' => $message
]
]
];
return $this->makeRequest('/send-message', $payload);
}
// Fungsi internal untuk eksekusi API
protected function makeRequest(string $endpoint, array $payload): array
{
$curl = \Config\Services::curlrequest();
try {
$response = $curl->post($this->baseUrl . $endpoint, [
'headers' => [
'Authorization' => $this->token . '.' . $this->secretKey,
'Content-Type' => 'application/json'
],
'json' => $payload,
'verify' => false // Sama seperti CURLOPT_SSL_VERIFYPEER = 0
]);
$result = json_decode($response->getBody(), true);
$statusCode = $response->getStatusCode();
return [
'success' => ($statusCode === 200 && !empty($result)),
'data' => $result,
'http_code' => $statusCode
];
} catch (\Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
// Bersihkan nomor HP ke format internasional
protected function sanitizePhone(string $phone): string
{
$phone = preg_replace('/[^0-9]/', '', $phone);
if (substr($phone, 0, 2) === '08') {
$phone = '62' . substr($phone, 1);
} elseif (substr($phone, 0, 1) === '8') {
$phone = '62' . $phone;
}
return $phone;
}
}

3
app/Libraries/Zoom/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/vendor
.idea
.idea/*

View File

@@ -0,0 +1,146 @@
<?php
/**
* @copyright https://github.com/UsabilityDynamics/zoom-api-php-client/blob/master/LICENSE
*/
namespace Zoom\Endpoint;
use Zoom\Interfaces\Request;
/**
* Class Meetings
* @package Zoom\Endpoint
*/
class Meetings extends Request {
/**
* Meetings constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct($apiKey, $apiSecret) {
parent::__construct($apiKey, $apiSecret);
}
/**
* List
*
* @param $userId
* @param array $query
* @return array|mixed
*/
public function list(string $userId, array $query = []) {
return $this->get("users/{$userId}/meetings", $query);
}
public function userInfo(string $email) {
return $this->get("users/me");
}
/**
* Create
*
* @param $userId
* @param array $data
* @return array|mixed
*/
public function create(string $userId, array $data = null) {
return $this->post("users/{$userId}/meetings", $data);
}
/**
* Meeting
*
* @param $meetingId
* @return array|mixed
*/
public function meeting(string $meetingId) {
return $this->get("meetings/{$meetingId}");
}
/**
* Remove
*
* @param $meetingId
* @return array|mixed
*/
public function remove(string $meetingId) {
return $this->delete("meetings/{$meetingId}");
}
/**
* Update
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function update(string $meetingId, array $data = []) {
return $this->patch("meetings/{$meetingId}", $data);
}
/**
* Status
*
* @param $meetingId
* @param array $data
* @return mixed
*/
public function status(string $meetingId, array $data = []) {
return $this->put("meetings/{$meetingId}/status", $data);
}
/**
* List Registrants
*
* @param $meetingId
* @param array $query
* @return array|mixed
*/
public function listRegistrants(string $meetingId, array $query = []) {
return $this->get("meetings/{$meetingId}/registrants", $query);
}
/**
* Add Registrant
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function addRegistrant(string $meetingId, $data = []) {
return $this->post("meetings/{$meetingId}/registrants", $data);
}
/**
* Update Registrant Status
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function updateRegistrantStatus(string $meetingId, array $data = []) {
return $this->put("meetings/{$meetingId}/registrants/status", $data);
}
/**
* Past Meeting
*
* @param $meetingUUID
* @return array|mixed
*/
public function pastMeeting(string $meetingUUID) {
return $this->get("past_meetings/{$meetingUUID}");
}
/**
* Past Meeting Participants
*
* @param $meetingUUID
* @param array $query
* @return array|mixed
*/
public function pastMeetingParticipants(string $meetingUUID, array $query = []) {
return $this->get("past_meetings/{$meetingUUID}/participants", $query);
}
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* @copyright https://github.com/UsabilityDynamics/zoom-api-php-client/blob/master/LICENSE
*/
namespace Zoom\Endpoint;
use Zoom\Interfaces\Request;
/**
* Class Recordings
* @package Zoom\Endpoint
*/
class Recordings extends Request {
/**
* Recordings constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct($apiKey, $apiSecret) {
parent::__construct($apiKey, $apiSecret);
}
/**
* List
*
* @param $userId
* @param array $query
* @return array|mixed
*/
public function listAll(string $userId, array $query = []) {
return $this->get("users/{$userId}/recordings", $query);
}
/**
* Meeting
*
* @param $meetingId
* @return array|mixed
*/
public function meeting(string $meetingId) {
return $this->get("meetings/{$meetingId}/recordings");
}
public function download(string $meetingId) {
return $this->get($meetingId);
}
/**
* Remove All
*
* @param $meetingId
* @param array $query
* @return array|mixed
*/
public function removeAll(string $meetingId, array $query = [ 'action' => 'trash' ]) {
return $this->delete("meetings/{$meetingId}/recordings", $query);
}
/**
* Remove
*
* @param $meetingId
* @param $recordingId
* @param array $query
* @return array|mixed
*/
public function remove(string $meetingId, string $recordingId, array $query = [ 'action' => 'trash' ]) {
return $this->delete("meetings/{$meetingId}/recordings/{$recordingId}", $query);
}
/**
* Recover All
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function recoverAll(string $meetingId, array $data = [ 'action' => 'recover' ]) {
return $this->put("meetings/{$meetingId}/recordings/status", $data);
}
/**
* Recover
*
* @param $meetingId
* @param $recordingId
* @param array $data
* @return array|mixed
*/
public function recover(string $meetingId, string $recordingId, array $data = [ 'action' => 'recover' ]) {
return $this->put("meetings/{$meetingId}/recordings/{$recordingId}/status", $data);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* @copyright https://github.com/UsabilityDynamics/zoom-api-php-client/blob/master/LICENSE
*/
namespace Zoom\Endpoint;
use Zoom\Interfaces\Request;
/**
* Class Reports
* @package Zoom\Interfaces
*/
class Reports extends Request {
/**
* Meetings constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct($apiKey, $apiSecret) {
parent::__construct($apiKey, $apiSecret);
}
/**
* Meeting Participants
*
* @param $meetingUUID
* @param array $query
* @return array|mixed
*/
public function meetingParticipants(string $meetingUUID, array $query = []) {
return $this->get("report/meetings/{$meetingUUID}/participants", $query);
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* @copyright https://github.com/UsabilityDynamics/zoom-api-php-client/blob/master/LICENSE
*/
namespace Zoom\Endpoint;
use Zoom\Interfaces\Request;
/**
* Class Users
* @package Zoom\Interfaces
*/
class Users extends Request {
/**
* Users constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct($apiKey, $apiSecret) {
parent::__construct($apiKey, $apiSecret);
}
/**
* List
*
* @param array $query
* @return array|mixed
*/
public function list( array $query = [] ) {
return $this->get( "users", $query );
}
/**
* Create
*
* @param array|null $data
* @return array|mixed
*/
public function create( array $data = null ) {
return $this->post( "users", $data );
}
/**
* Retrieve
*
* @param $userID
* @param array $query
* @return array|mixed
*/
public function retrieve( string $userID, array $query = [] ) {
return $this->get( "users/{$userID}", $query );
}
/**
* Remove
*
* @param $userId
* @return array|mixed
*/
public function remove( string $userId ) {
return $this->delete( "users/{$userId}" );
}
/**
* Update
*
* @param $userId
* @param array $data
* @return array|mixed
*/
public function update( string $userId, array $data = [] ) {
return $this->patch( "users/{$userId}", $data );
}
}

View File

@@ -0,0 +1,143 @@
<?php
/**
* @copyright https://github.com/UsabilityDynamics/zoom-api-php-client/blob/master/LICENSE
*/
namespace Zoom\Endpoint;
use Zoom\Interfaces\Request;
/**
* Class Webinars
* @package Zoom\Endpoint
*/
class Webinars extends Request {
/**
* webinars constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct($apiKey, $apiSecret) {
parent::__construct($apiKey, $apiSecret);
}
/**
* List
*
* @param $userId
* @param array $query
* @return array|mixed
*/
public function list(string $userId, array $query = []) {
return $this->get("users/{$userId}/webinars", $query);
}
/**
* Create
*
* @param $userId
* @param array $data
* @return array|mixed
*/
public function create(string $userId, array $data = null) {
return $this->post("users/{$userId}/webinars", $data);
}
/**
* Meeting
*
* @param $meetingId
* @return array|mixed
*/
public function meeting(string $meetingId) {
return $this->get("webinars/{$meetingId}");
}
/**
* Remove
*
* @param $meetingId
* @return array|mixed
*/
public function remove(string $meetingId) {
return $this->delete("webinars/{$meetingId}");
}
/**
* Update
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function update(string $meetingId, array $data = []) {
return $this->patch("webinars/{$meetingId}", $data);
}
/**
* Status
*
* @param $meetingId
* @param array $data
* @return mixed
*/
public function status(string $meetingId, array $data = []) {
return $this->put("webinars/{$meetingId}/status", $data);
}
/**
* List Registrants
*
* @param $meetingId
* @param array $query
* @return array|mixed
*/
public function listRegistrants(string $meetingId, array $query = []) {
return $this->get("webinars/{$meetingId}/registrants", $query);
}
/**
* Add Registrant
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function addRegistrant(string $meetingId, $data = []) {
return $this->post("webinars/{$meetingId}/registrants", $data);
}
/**
* Update Registrant Status
*
* @param $meetingId
* @param array $data
* @return array|mixed
*/
public function updateRegistrantStatus(string $meetingId, array $data = []) {
return $this->put("webinars/{$meetingId}/registrants/status", $data);
}
/**
* Past Meeting
*
* @param $meetingUUID
* @return array|mixed
*/
public function pastMeeting(string $meetingUUID) {
return $this->get("past_webinars/{$meetingUUID}");
}
/**
* Past Meeting Participants
*
* @param $meetingUUID
* @param array $query
* @return array|mixed
*/
public function pastMeetingParticipants(string $meetingUUID, array $query = []) {
return $this->get("past_webinars/{$meetingUUID}/participants", $query);
}
}

View File

@@ -0,0 +1,199 @@
<?php
/**
* @copyright https://github.com/UsabilityDynamics/zoom-api-php-client/blob/master/LICENSE
*/
namespace Zoom\Interfaces;
use Firebase\JWT\JWT;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Psr7\Response;
class Request {
/**
* @var
*/
protected $apiKey;
/**
* @var
*/
protected $apiSecret;
/**
* @var Client
*/
protected $client;
/**
* @var string
*/
public $apiPoint = 'https://api.zoom.us/v2/';
/**
* Request constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct( $apiKey, $apiSecret ) {
$this->apiKey = $apiKey;
$this->apiSecret = $apiSecret;
$this->client = new Client();
}
/**
* Headers
*
* @return array
*/
protected function headers(): array {
return [
'Authorization' => 'Bearer ' . $this->generateJWT(),
'Content-Type' => 'application/json',
'Accept' => 'application/json',
];
}
/**
* Generate J W T
*
* @return string
*/
protected function generateJWT() {
$token = [
'iss' => $this->apiKey,
'exp' => time() + 60,
];
return JWT::encode($token, $this->apiSecret,'HS256');
}
/**
* Get
*
* @param $method
* @param array $fields
* @return array|mixed
*/
protected function get($method, $fields = []) {
try {
$response = $this->client->request('GET', $this->apiPoint . $method, [
'query' => $fields,
'headers' => $this->headers(),
]);
return $this->result($response);
} catch (ClientException $e) {
return (array)json_decode($e->getResponse()->getBody()->getContents());
}
}
/**
* Post
*
* @param $method
* @param $fields
* @return array|mixed
*/
protected function post($method, $fields) {
$body = \json_encode($fields, JSON_PRETTY_PRINT);
try {
$response = $this->client->request('POST', $this->apiPoint . $method,
['body' => $body, 'headers' => $this->headers()]);
return $this->result($response);
} catch (ClientException $e) {
return (array)json_decode($e->getResponse()->getBody()->getContents());
}
}
/**
* Patch
*
* @param $method
* @param $fields
* @return array|mixed
*/
protected function patch($method, $fields) {
$body = \json_encode($fields, JSON_PRETTY_PRINT);
try {
$response = $this->client->request('PATCH', $this->apiPoint . $method,
['body' => $body, 'headers' => $this->headers()]);
return $this->result($response);
} catch (ClientException $e) {
return (array)json_decode($e->getResponse()->getBody()->getContents());
}
}
/**
* Put
*
* @param $method
* @param $fields
* @return array|mixed
*/
protected function put($method, $fields) {
$body = \json_encode($fields, JSON_PRETTY_PRINT);
try {
$response = $this->client->request('PUT', $this->apiPoint . $method,
['body' => $body, 'headers' => $this->headers()]);
return $this->result($response);
} catch (ClientException $e) {
return (array)json_decode($e->getResponse()->getBody()->getContents());
}
}
/**
* Delete
*
* @param $method
* @param $fields
* @return array|mixed
*/
protected function delete($method, $fields = []) {
$body = \json_encode($fields, JSON_PRETTY_PRINT);
try {
$response = $this->client->request('DELETE', $this->apiPoint . $method,
['body' => $body, 'headers' => $this->headers()]);
return $this->result($response);
} catch (ClientException $e) {
return (array)json_decode($e->getResponse()->getBody()->getContents());
}
}
/**
* Result
*
* @param Response $response
* @return mixed
*/
protected function result(Response $response) {
$result = json_decode((string)$response->getBody(), true);
$result['code'] = $response->getStatusCode();
return $result;
}
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Zoom Video Communications
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
# PHP
Zoom REST API's using PHP
Visit https://zoom.us/developer for more details
## Support
For any questions or issues, please visit our new Community Support Forum at https://devforum.zoom.us/

View File

@@ -0,0 +1,119 @@
<?php
namespace Zoom;
use Zoom\Endpoint\Users;
use GuzzleHttp\Client;
class ZoomAPI
{
/**
* @var null
*/
private $apiKey = null;
/**
* @var null
*/
private $apiSecret = null;
/**
* @var null
*/
private $users = null;
protected string $accessToken;
protected $client;
/**
* Retorna uma instância única de uma classe.
*
* @staticvar Singleton $instance A instância única dessa classe.
*
* @return Singleton A Instância única.
*/
public function getInstance()
{
static $users = null;
if (null === $users) {
$this->users = new Users($this->apiKey, $this->apiSecret);
}
return $users;
}
/**
* Zoom constructor.
* @param $apiKey
* @param $apiSecret
*/
public function __construct($apiKey, $apiSecret, $account_id)
{
$this->apiKey = $apiKey;
$this->apiSecret = $apiSecret;
$client = new Client([
'headers' => [
'Authorization' => 'Basic ' . base64_encode($this->apiKey . ':' . $this->apiSecret),
'Host' => 'zoom.us',
],
]);
$response = $client->request('POST', "https://zoom.us/oauth/token", [
'form_params' => [
'grant_type' => 'account_credentials',
'account_id' => $account_id,
],
]);
$responseBody = json_decode($response->getBody(), true);
// print_r($responseBody);
// die;
$this->accessToken = $responseBody['access_token'];
// return $responseBody['access_token'];
}
public function createMeeting($data)
{
$now = date("Y-m-d\TH:i", strtotime(date('Y-m-d H:i:s', time())));
$postFields = [
'topic' => $data['title'],
'type' => 2, // Scheduled meeting
'start_time' => $now, // Meeting start time in ISO 8601 format
'duration' => 60 * 12, // Meeting duration in minutes
'timezone' => 'UTC+07',
'agenda' => $data['description']
];
$this->client = new Client([
'base_uri' => 'https://api.zoom.us/v2/',
'headers' => [
'Authorization' => 'Bearer ' . $this->accessToken,
'Content-Type' => 'application/json',
],
]);
try {
$response = $this->client->request('POST', 'users/me/meetings', [
'json' => $postFields,
]);
$res = json_decode($response->getBody(), true);
return [
'status' => true,
'data' => $res,
];
} catch (\Throwable $th) {
return [
'status' => false,
'message' => $th->getMessage(),
];
}
}
/*Functions for management of users*/
// public function createUser()
// {
// $createAUserArray['action'] = 'create';
// $createAUserArray['email'] = $_POST['email'];
// $createAUserArray['user_info'] = $_POST['user_info'];
// return $this->users->create($createAUserArray);
// }
}

View File

@@ -0,0 +1,13 @@
{
"name": "zoom/zoom",
"description": "Api Zoom",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"guzzlehttp/guzzle": "^7.8",
"firebase/php-jwt": "^6.9"
},
"autoload": {
"psr-4": {"Zoom\\": ""}
}
}

View File

@@ -0,0 +1,8 @@
<?php
require_once __DIR__ . '/vendor/autoload.php';
$zoom = new \Zoom\ZoomAPI('AAAAA', 'BBBBB');
var_dump($zoom->createUser() );
exit();