diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 36eb93c..87d462a 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -111,4 +111,17 @@ $routes->group('admin/cloudflare', ['namespace' => 'App\Controllers\Admin\Cloudf $routes->get('reload/(:alphanum)', 'RecordController::reload/$1'); $routes->get('download/(:alpha)', 'RecordController::download/$1'); }); + $routes->group('firewall', function ($routes) { + $routes->get('/', 'FirewallController::index'); + $routes->get('create', 'FirewallController::create_form'); + $routes->post('create', 'FirewallController::create'); + $routes->get('view/(:alphanum)', 'FirewallController::view/$1'); + $routes->get('delete/(:alphanum)', 'FirewallController::delete/$1'); + $routes->get('sync/(:alphanum)', 'FirewallController::sync/$1'); + $routes->get('toggle/(:alphanum)/(:any)', 'FirewallController::toggle/$1/$2'); + $routes->post('batchjob', 'FirewallController::batcjob'); + $routes->post('batchjob_delete', 'FirewallController::batcjob_delete'); + $routes->get('reload/(:alphanum)', 'FirewallController::reload/$1'); + $routes->get('download/(:alpha)', 'FirewallController::download/$1'); + }); }); diff --git a/app/Controllers/Admin/Cloudflare/FirewallController.php b/app/Controllers/Admin/Cloudflare/FirewallController.php new file mode 100644 index 0000000..5b68ad5 --- /dev/null +++ b/app/Controllers/Admin/Cloudflare/FirewallController.php @@ -0,0 +1,262 @@ +class_name .= "Firewall"; + $this->class_path .= $this->class_name; + $this->title = lang("{$this->class_path}.title"); + $this->helper = new FirewallHelper(); + } + final protected function getModel(): FirewallModel + { + if ($this->model === null) { + $this->model = new FirewallModel(); + } + return $this->model; + } + final protected function getMyLibrary(): Firewall + { + if (!isset($this->_myLibrays[$this->_zone_entity->getPK()])) { + $this->_myLibrays[$this->_zone_entity->getPK()] = new Firewall($this->_zone_entity); + } + return $this->_myLibrays[$this->_zone_entity->getPK()]; + } + protected function getFormFieldOption(string $field, array $options = []): array + { + switch ($field) { + case $this->getModel()::PARENT: + // $this->getZoneModel()->where('status', 'active'); + $options[$field] = $this->getZoneModel()->getFormFieldOption($field); + // echo $this->getAccountModel()->getLastQuery(); + // dd($options); + break; + default: + $options = parent::getFormFieldOption($field, $options); + break; + } + return $options; + } + //전송된 데이터 + protected function getFormData(string $field, array $formDatas): array + { + switch ($field) { + case 'hosts': + $formDatas[$field] = explode("\n", $this->request->getVar($field)); + if (!is_array($formDatas[$field]) || !count($formDatas[$field])) { + throw new \Exception("호스트명이 정의되지 않았습니다."); + } + break; + default: + $formDatas = parent::getFormData($field, $formDatas); + break; + } + return $formDatas; + } + private function init(string $action, array $fields = []): void + { + $this->action = $action; + $this->fields = count($fields) ? $fields : [$this->getModel()::PARENT, 'mode', 'description', 'expression', 'ref', 'paused', 'updated_at', 'created_at']; + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + $this->filter_fields = [$this->getModel()::PARENT, 'mode', 'paused']; + $this->field_options = $this->getFormFieldOptions($this->filter_fields); + $this->batchjob_fields = ['mode', 'paused']; + } + //생성 + public function create_form(): RedirectResponse|string + { + $this->init('create', [$this->getModel()::PARENT, 'mode', 'description', 'expression', 'paused']); + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + //부모데이터 정의 + $parent_field = $this->getModel()::PARENT; + $this->$parent_field = $this->request->getVar($parent_field) ?: DEFAULTS["EMPTY"]; + return $this->create_form_procedure(); + } + protected function create_process(): void + { + //DB작업도 Socket에서 다 처리하므로 parent::create_process()하면 않됨 + $this->create_validate($this->action, $this->fields); + $this->formDatas = $this->getFormDatas(); + //부모데이터정의 + $this->_zone_entity = $this->getZoneModel()->getEntityByPK($this->formDatas[$this->getModel()::PARENT]); + $this->entity = $this->getMyLibrary()->create( + $this->formDatas['mode'], + $this->formDatas['description'], + $this->formDatas['expression'], + $this->formDatas['paused'], + $this->formDatas['ref'] + ); + log_message("debug", message: "Firewall:{$this->entity->getTitle()} 생성 작업을 완료하였습니다."); + } + protected function create_process_result(): RedirectResponse|string + { + $this->init(__FUNCTION__); + return $this->view_process_result(); + } + public function create(): RedirectResponse|string + { + $this->init(__FUNCTION__, [$this->getModel()::PARENT, 'mode', 'description', 'expression', 'paused']); + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + return $this->create_procedure(); + } + //수정 (modify,toggle,batchjob사용) + public function modify_form(int $uid): RedirectResponse|string + { + $this->init('modify', [$this->getModel()::PARENT, 'mode', 'description', 'expression', 'paused']); + return $this->modify_form_procedure($uid); + } + protected function modify_process(mixed $uid): void + { + //DB작업도 Socket에서 다 처리하므로 parent::modify_process($uid)하면 않됨 + $this->modify_validate($this->action, $this->fields); + $this->formDatas = $this->getFormDatas(); + //자신정보정의 + $this->entity = $this->getModel()->getEntityByPK($uid); + if ($this->entity === null) { + throw new \Exception("{$uid} 정보를 찾을수 없습니다."); + } + //부모데이터정의 + $this->_zone_entity = $this->getZoneModel()->getEntityByPK($this->entity->getParent()); + //Socket처리 + $this->entity = $this->getMyLibrary()->modify($this->entity, $this->formDatas); + } + public function modify(int $uid): RedirectResponse|string + { + $this->init(__FUNCTION__, [$this->getModel()::PARENT, 'mode', 'description', 'expression', 'paused']); + return $this->modify_procedure($uid); + } + //일괄처리작업 + public function batcjob(): RedirectResponse + { + $this->init(__FUNCTION__); + return $this->batcjob_procedure(); + } + //View + //create_process_result에서 결과값을 entitys에 저장하고 호출하기때문에 아래와 같이 처리함 + protected function view_process(mixed $uid): void + { + //자신정보정의 + $entity = $this->getModel()->getEntityByPK($uid); + if ($entity === null) { + throw new \Exception("Zone {$uid} 정보를 찾을수 없습니다."); + } + $this->entitys = [$entity]; + // dd($this->entitys); + } + //create_process_result에서 같이 사용한다는 점 주의 + protected function view_process_result(): string + { + helper(['form']); + $this->forms = ['attributes' => ['method' => "post",], 'hiddens' => []]; + return view( + strtolower($this->view_path . $this->class_path . "/view"), + data: ['viewDatas' => $this->getViewDatas()] + ); + } + public function view(string $uid): RedirectResponse|string + { + $this->init(__FUNCTION__); + return $this->view_procedure($uid); + } + //삭제 + protected function delete_process(mixed $uid): void + { + //DB작업도 Socket에서 다 처리하므로 parent::delete_process($uid)하면 않됨 + //자신정보정의 + $this->entity = $this->getModel()->getEntityByPK($uid); + if ($this->entity === null) { + throw new \Exception("{$uid} 정보를 찾을수 없습니다."); + } + //부모데이터정의 + $this->_zone_entity = $this->getZoneModel()->getEntityByPK($this->entity->getParent()); + //Cloudflare 삭제 + $this->entity = $this->getMyLibrary()->delete($this->entity); + } + // 리스트 + protected function list_entitys_process(): array + { + $this->list_condition_process(); + //기본Soring처리 + $this->getModel()->orderBy(ZoneModel::TABLE . "." . ZoneModel::TITLE . " ASC ," . $this->getModel()::TITLE . " ASC"); + //Sorting 처리 + $this->order_field = $this->request->getVar('order_field') ?: DEFAULTS['EMPTY']; + $this->order_value = $this->request->getVar('order_value') ?: DEFAULTS['EMPTY']; + if ($this->order_field !== DEFAULTS['EMPTY'] && $this->order_value !== DEFAULTS['EMPTY']) { + $this->getModel()->orderBy(sprintf( + "%s.%s %s", + $this->getModel()::TABLE, + $this->order_field, + $this->order_value + )); + } + $this->getModel()->limit($this->per_page, $this->page * $this->per_page - $this->per_page); + //Join을 해서 도메인부터 Sorting하기위함 + $this->getModel()->join(ZoneModel::TABLE, sprintf( + "%s.%s=%s.%s", + $this->getModel()::TABLE, + $this->getModel()::PARENT, + ZoneModel::TABLE, + ZoneModel::PK + )); + $entitys = $this->getModel()->select($this->getModel()::TABLE . '.*')->findAll(); + log_message("debug", $this->getModel()->getLastQuery()); + return $entitys; + } + public function index(): string + { + $this->init(__FUNCTION__); + return $this->list_procedure(); + } + // Download + public function download(string $output_type, mixed $uid = false): DownloadResponse|string + { + $this->init(__FUNCTION__); + return $this->download_procedure($output_type, $uid); + } + //Sync작업 + protected function sync_process(string $uid): void + { + //자신정보정의 + $this->entity = $this->getModel()->getEntityByPK($uid); + if ($this->entity === null) { + throw new \Exception("{$uid} 정보를 찾을수 없습니다."); + } + //부모데이터정의 + $this->_zone_entity = $this->getZoneModel()->getEntityByPK($this->entity->getParent()); + //Socket처리 + $this->entity = $this->getMyLibrary()->sync($this->entity); + } + public function sync(string $uid): RedirectResponse + { + return $this->sync_procedure($uid); + } + //reload Firewall By Zone + protected function reload_process(mixed $uid): void + { + $this->_zone_entity = $this->getZoneModel()->getEntityByPK($uid); + if ($this->_zone_entity === null) { + throw new \Exception("Zone: {$uid} 정보를 찾을수 없습니다."); + } + $this->getMyLibrary()->reload(); + } + public function reload(string $uid): RedirectResponse + { + return $this->reload_procedure($uid); + } +} diff --git a/app/Controllers/Admin/Cloudflare/RecordController.php b/app/Controllers/Admin/Cloudflare/RecordController.php index f037037..8b13596 100644 --- a/app/Controllers/Admin/Cloudflare/RecordController.php +++ b/app/Controllers/Admin/Cloudflare/RecordController.php @@ -72,7 +72,7 @@ class RecordController extends CloudflareController private function init(string $action, array $fields = []): void { $this->action = $action; - $this->fields = count($fields) ? $fields : [$this->getModel()::PARENT, 'host', 'type', 'content', 'proxied', 'updated_at', 'created_at', 'created_at']; + $this->fields = count($fields) ? $fields : [$this->getModel()::PARENT, 'host', 'type', 'content', 'proxied', 'updated_at', 'created_at']; $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); $this->filter_fields = [$this->getModel()::PARENT, 'type', 'proxied', 'fixed']; $this->field_options = $this->getFormFieldOptions($this->filter_fields); @@ -176,7 +176,6 @@ class RecordController extends CloudflareController } //View //create_process_result에서 결과값을 entitys에 저장하고 호출하기때문에 아래와 같이 처리함 - protected function view_process(mixed $uid): void { //자신정보정의 @@ -216,7 +215,7 @@ class RecordController extends CloudflareController //Cloudflare 삭제 $this->entity = $this->getMyLibrary()->delete($this->entity); } - // 리스트 + //리스트 protected function list_entitys_process(): array { $this->list_condition_process(); diff --git a/app/Entities/Cloudflare/FirewallEntity.php b/app/Entities/Cloudflare/FirewallEntity.php new file mode 100644 index 0000000..1dac62c --- /dev/null +++ b/app/Entities/Cloudflare/FirewallEntity.php @@ -0,0 +1,31 @@ +getPK()}|{$this->getParent()}|{$this->getTitle()}|{$this->attributes['host']}|{$this->attributes['content']}|{$this->attributes['proxied']}|{$this->attributes['fixed']}|{$this->attributes['locked']}"; + } + public function getPK(): string + { + return $this->attributes[FirewallModel::PK]; + } + public function getTitle(): string + { + return $this->attributes[FirewallModel::TITLE]; + } + public function setTitle(string $title): void + { + $this->attributes[FirewallModel::TITLE] = $title; + } + //Common Function + public function getParent(): string + { + return $this->attributes[FirewallModel::PARENT]; + } +} diff --git a/app/Helpers/Cloudflare/FirewallHelper.php b/app/Helpers/Cloudflare/FirewallHelper.php new file mode 100644 index 0000000..1868d2d --- /dev/null +++ b/app/Helpers/Cloudflare/FirewallHelper.php @@ -0,0 +1,125 @@ +getFieldRule($viewDatas['action'], $field), 'required') !== false) ? ["class" => "form-control", "required" => "", ...$extras] : ["class" => "form-control", ...$extras]; + } + $value = $value ?: DEFAULTS['EMPTY']; + switch ($field) { + case FirewallModel::PARENT: + //기존 작성하던값old($field)가 있으면 그값을 넣고 없으면 부모값이 있으면 넣고 없으면 entiy가 있으면 그값을 넣고 없으면 디폴트값을 넣는다. + $value = $value ?: (isset($viewDatas[$field]) ? $viewDatas[$field] : (isset($viewDatas['entity']) ? $viewDatas['entity']->getParent() : DEFAULTS['EMPTY'])); + + $extra_class = isset($extras['class']) ? 'select-field ' . $extras['class'] : 'select-field'; + $form = form_dropdown($field, [ + "" => lang($viewDatas['class_path'] . '.label.' . $field) . ' 선택', + ] + $viewDatas['field_options'][$field], $value, [ + 'class' => $extra_class, + ...array_diff_key($extras, ['class' => '']) + ]); + break; + case FirewallModel::TITLE: //host + $form = form_input($field, $value, $extras); + break; + case 'hosts': + $form = form_textarea($field, html_entity_decode($value), [ + 'rows' => '5', + ...$extras + ]); + break; + case 'expression': + $form = form_input($field, $value, ["placeholder" => "예)123.123.123.123", ...$extras]); + break; + case "mode": + case "paused": + $form = form_dropdown($field, [ + "" => lang($viewDatas['class_path'] . '.label.' . $field) . ' 선택', + ] + $viewDatas['field_options'][$field], $value, $extras); + break; + default: + $form = parent::getFieldForm($field, $value, $viewDatas, $extras); + break; + } + return $form; + } // + public function getFieldView(string $field, array $viewDatas, array $extras = []): string + { + $value = $viewDatas['entity']->$field ?: DEFAULTS['EMPTY']; + switch ($field) { + case FirewallModel::PARENT: + if ($this->old_parent === $viewDatas['entity']->getParent()) { + $value = ""; + } else { + $value = anchor( + current_url() . "/reload/" . $viewDatas['entity']->getParent(), + ICONS["RELOAD"], + [ + "class" => "btn btn-sm btn-primary btn-circle", + "target" => "_self", + ] + ) . " " . form_label( + $viewDatas['field_options'][$field][$value], + 'label_zones', + ['class' => "label_zones", ...$extras] + ); + } + $this->old_parent = $viewDatas['entity']->getParent(); + break; + case FirewallModel::TITLE: + $value = parent::getFieldView($field, $viewDatas, ['class' => "label_hosts", ...$extras]); + break; + default: + $value = parent::getFieldView($field, $viewDatas, $extras); + break; + } + return $value; + } // + + public function getListRowColor($entity): string + { + return $entity->paused != 'on' ? 'class="table-danger"' : ""; + } + public function getListButton(string $action, array $viewDatas, array $extras = []): string + { + switch ($action) { + case 'modify': + $checkbox = ""; + if ($viewDatas['entity']->fixed != 'on') { + $pk = $viewDatas['entity']->getPK(); + $oldBatchJobUids = old("batchjob_uids") ?? []; + $oldBatchJobUids = is_array($oldBatchJobUids) ? $oldBatchJobUids : [$oldBatchJobUids]; + $checkbox = form_checkbox([ + "id" => "checkbox_uid_{$pk}", + "name" => "batchjob_uids[]", + "value" => $pk, + "class" => "batchjobuids_checkboxs", + "checked" => in_array($pk, $oldBatchJobUids) + ]); + } + $extras = ["target" => "_self", ...$extras]; + $action = $checkbox . anchor( + current_url() . "/sync/" . $viewDatas['entity']->getPK(), + $viewDatas['cnt'], + $extras + ); + break; + default: + $action = parent::getListButton($action, $viewDatas, $extras); + break; + } + return $action; + } +} diff --git a/app/Language/en/Cloudflare/Firewall.php b/app/Language/en/Cloudflare/Firewall.php new file mode 100644 index 0000000..5a54a59 --- /dev/null +++ b/app/Language/en/Cloudflare/Firewall.php @@ -0,0 +1,27 @@ + "Record정보", + 'label' => [ + 'uid' => "번호", + 'zone_uid' => "도메인", + 'description' => "설명", + 'mode' => "Mode", + 'expression' => "Rule", + 'ref' => "REF", + 'paused' => "상태", + 'updated_at' => "수정일", + 'created_at' => "작성일", + ], + "ZONE_UID" => [], + "MODE" => [ + 'simulate' => 'simulate', + 'ban' => 'ban', + 'challenge' => 'challenge', + 'js_challenge' => 'js_challenge', + 'managed_challenge' => 'managed_challenge', + ], + "PAUSED" => [ + "on" => "사용", + "off" => "사용 않함", + ], +]; diff --git a/app/Models/Cloudflare/FirewallModel.php b/app/Models/Cloudflare/FirewallModel.php new file mode 100644 index 0000000..50600e5 --- /dev/null +++ b/app/Models/Cloudflare/FirewallModel.php @@ -0,0 +1,97 @@ +table}.{$field}]" : ""; + break; + case self::PARENT: + $rule = "required|trim|alpha_numeric"; + break; + case self::TITLE: + case "expression": + $rule = "required|trim|string"; + break; + case "ref": + $rule = "if_exist|trim|string"; + break; + case "locked": + $rule = "required|in_list[on,off]"; + break; + default: + $rule = parent::getFieldRule($action, $field); + break; + } + return $rule; + } + public function getFormFieldInputOption(string $field, array $options = []): array + { + switch ($field) { + default: + $this->orderBy(self::TITLE, 'asc'); + $options = parent::getFormFieldInputOption($field, $options); + break; + } + return $options; + } + public function getEntityByPK(string $uid): null|FirewallEntity + { + $this->where(self::PK, $uid); + return $this->getEntity(); + } + public function getEntityByID(string $id): null|FirewallEntity + { + $this->where(self::TITLE, $id); + return $this->getEntity(); + } + public function getEntitysByParent(ZoneEntity $zone_entity) + { + $this->where(self::PARENT, $zone_entity->getPK()); + return $this->getEntitys(); + } + //create용 + public function create(array $formDatas = []): FirewallEntity + { + return $this->create_process(new FirewallEntity(), $formDatas); + } + //modify용 + public function modify(FirewallEntity $entity, array $formDatas): FirewallEntity + { + return $this->modify_process($entity, $formDatas); + } + //List 검색용 + public function setList_WordFilter(string $word, $field = null): void + { + parent::setList_WordFilter($word, $field); + $this->orLike(self::TABLE . '.mode', $word, 'both'); + } +} diff --git a/app/Services/Cloudflare/Firewall.php b/app/Services/Cloudflare/Firewall.php new file mode 100644 index 0000000..a85f5cd --- /dev/null +++ b/app/Services/Cloudflare/Firewall.php @@ -0,0 +1,162 @@ +_parent_entity = $zone_entity; + $account_entity = $this->getAccountModel()->getEntityByPK($this->getParentEntity()->getParent()); + if ($account_entity === null) { + throw new \Exception("해당 계정정보를 찾을수 없습니다."); + } + $auth_entity = $this->getAuthModel()->getEntityByPK($account_entity->getParent()); + if ($auth_entity === null) { + throw new \Exception("해당 계정정보를 찾을수 없습니다."); + } + parent::__construct($auth_entity); + } + protected function getParentEntity(): ZoneEntity + { + if ($this->_parent_entity === null) { + throw new \Exception(__FUNCTION__ . "에서 부모정보가 없습니다."); + } + return $this->_parent_entity; + } + protected function getModel(): FirewallModel + { + if ($this->_model === null) { + $this->_model = new FirewallModel(); + } + return $this->_model; + } + protected function getAccountModel(): AccountModel + { + if ($this->_accountModel === null) { + $this->_accountModel = new AccountModel(); + } + return $this->_accountModel; + } + protected function getArrayByResult(\stdClass $result, array $formDatas = []): array + { + // log_message("debug", var_export($result, true)); + $formDatas[FirewallModel::PK] = $result->id; + $formDatas[FirewallModel::PARENT] = $result->zone_id; + $formDatas[FirewallModel::TITLE] = $result->name; + $formDatas['action'] = $result->action; + $formDatas['description'] = $result->description; + $formDatas['priority'] = (int)$result->priority; + $formDatas['expression'] = $result->expression; + $formDatas['paused'] = isset($result->paused) && $result->paused ? "off" : "on"; + $formDatas['updated_at'] = date("Y-m-d H:i:s"); + $formDatas['created_at'] = $result->created_on; + // log_message("debug", print_r($formDatas, true)); + return $formDatas; + } + public function create(string $mode, string $description, string $expression, string $paused, string $ref = "FIL-100"): FirewallEntity + { + //Socket용 + //호스트생성을 위해 Cloudflare에 전송 + $datas = [ + 'action' => [ + 'mode' => $mode, + 'response' => [ + 'body' => "This request has been rate-limited.", + 'content_type' => 'text/xml', + ], + 'timeout' => 86400, + ], + 'filter' => [ + 'description' => $description, + 'expression' => $expression, + 'paused' => $paused === 'on' ? true : false, + "ref" => $ref + ] + ]; + $response = $this->getMySocket()->post("zones/{$this->getParentEntity()->getPK()}/firewall/rules", $datas); + $body = json_decode($response->getBody()); + //DB생성 + return $this->getModel()->create($this->getArrayByResult($body->result)); + } + public function modify(FirewallEntity $entity, array $formDatas): FirewallEntity + { + //TTL값은 CDN(proxied)가 사용함일때는 무조건 1, 않함일때는 120이 적용 + $datas = [ + 'action' => [ + 'mode' => $formDatas['mode'], + 'response' => [ + 'body' => "This request has been rate-limited.", + 'content_type' => 'text/xml', + ], + 'timeout' => 86400, + ], + 'filter' => [ + 'description' => $formDatas['description'], + 'expression' => $formDatas['expression'], + 'paused' => $formDatas['paused'] === 'on' ? true : false, + "ref" => $formDatas['ref'] + ] + ]; + // 인코딩된 JSON을 확인 + // throw new \Exception("Firewall:" . __FUNCTION__ . "\n" . json_encode($datas, JSON_PRETTY_PRINT) . "\n" . var_export($datas, true)); + $response = $this->getMySocket()->put("zones/{$this->getParentEntity()->getPK()}/firewall/rules/{$entity->getPK()}", $datas); + $body = json_decode($response->getBody()); + // DB 수정 + return $this->getModel()->modify($entity, $this->getArrayByResult($body->result)); + } + public function delete(FirewallEntity $entity): FirewallEntity + { + $this->getMySocket()->delete("zones/{$this->getParentEntity()->getPK()}/firewall/rules/{$entity->getPK()}"); + //DB삭제 + $this->getModel()->delete($entity->getPK()); + log_message("debug", $this->getModel()->getLastQuery()); + return $entity; + } + public function sync(FirewallEntity $entity): FirewallEntity + { + // 기존 Sync형태 + $response = $this->getMySocket()->get("zones/{$this->getParentEntity()->getPK()}/firewall/rules/{$entity->getPK()}"); + $body = json_decode($response->getBody()); + // DB수정 + // log_message("debug", var_export($cf->result, true)); + $entity = $this->getModel()->modify($entity, $this->getArrayByResult($body->result)); + return $entity; + } + //Reload + public function reload(): array + { + log_message("notice", "\n-----------Zone {$this->getParentEntity()->getTitle()}의 Firewall 처리 시작-----------"); + $entitys = []; + try { + $results_array = $this->reload_procedure("zones/{$this->getParentEntity()->getPK()}/dns_records"); + if (count(value: $results_array) > 0) { + foreach ($results_array as $results) { + foreach ($results as $result) { + $formDatas = $this->getArrayByResult($result); + $entitys[$formDatas[FirewallModel::PK]] = $this->getModel()->modify(new FirewallEntity(), $formDatas); + } + } + //부모키를 기준으로 CF에 존재하지 않는 데이터 DB삭제 + $this->getModel()->where(FirewallModel::PARENT, $this->getParentEntity()->getPK()); + $this->getModel()->whereNotIn(FirewallModel::PK, array_keys($entitys)); + $this->getModel()->delete(); + log_message("debug", $this->getModel()->getLastQuery()); + } + } catch (\Exception $e) { + log_message("error", $e->getMessage()); + throw new \Exception($e->getMessage()); + } + log_message("notice", "\n-----------Zone {$this->getParentEntity()->getTitle()}의 Firewall처리[" . count($entitys) . "개] 완료-----------"); + return $entitys; + } +} diff --git a/app/Views/layouts/admin/left_menu/cloudflare.php b/app/Views/layouts/admin/left_menu/cloudflare.php index 8850010..186bee2 100644 --- a/app/Views/layouts/admin/left_menu/cloudflare.php +++ b/app/Views/layouts/admin/left_menu/cloudflare.php @@ -17,4 +17,7 @@
Record
+
+ Firewall +
\ No newline at end of file