load->model('user_model'); if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } // Load language files $this->lang->load('notes'); } private function is_public_station_diary_enabled() { $configValue = $this->config->item('public_station_diary_enabled'); if ($configValue === NULL) { $configValue = TRUE; } $optionValue = $this->optionslib->get_option('public_station_diary_enabled'); if ($optionValue !== NULL && $optionValue !== '') { return ($optionValue === '1' || $optionValue === 'true' || $optionValue === 1 || $optionValue === TRUE); } return (bool)$configValue; } private function handle_diary_images_upload($note_id) { if (!isset($_FILES['diary_images']) || !isset($_FILES['diary_images']['name']) || !is_array($_FILES['diary_images']['name'])) { return null; } $names = array_filter($_FILES['diary_images']['name']); if (empty($names)) { return null; } $noteResult = $this->note->view($note_id); if ($noteResult->num_rows() === 0) { return 'Unable to attach images: note not found.'; } $noteRow = $noteResult->row(); if (strtoupper(trim((string)$noteRow->cat)) !== 'STATION DIARY') { return 'Images are only supported for Station Diary entries.'; } $user_id = (int)$this->session->userdata('user_id'); $uploadDir = FCPATH . 'uploads/diary/' . $user_id . '/'; if (!is_dir($uploadDir)) { if (!@mkdir($uploadDir, 0755, TRUE)) { return 'Unable to create upload directory.'; } } $this->load->library('upload'); $this->load->library('image_lib'); $errors = array(); $savedImages = array(); $totalFiles = count($_FILES['diary_images']['name']); for ($i = 0; $i < $totalFiles; $i++) { if (empty($_FILES['diary_images']['name'][$i])) { continue; } $_FILES['single_diary_image']['name'] = $_FILES['diary_images']['name'][$i]; $_FILES['single_diary_image']['type'] = $_FILES['diary_images']['type'][$i]; $_FILES['single_diary_image']['tmp_name'] = $_FILES['diary_images']['tmp_name'][$i]; $_FILES['single_diary_image']['error'] = $_FILES['diary_images']['error'][$i]; $_FILES['single_diary_image']['size'] = $_FILES['diary_images']['size'][$i]; $uploadConfig = array( 'upload_path' => $uploadDir, 'allowed_types' => 'jpg|jpeg|png|gif|webp', 'max_size' => 2048, 'encrypt_name' => TRUE, 'detect_mime' => TRUE, 'mod_mime_fix' => TRUE, ); $this->upload->initialize($uploadConfig); if (!$this->upload->do_upload('single_diary_image')) { $errors[] = trim(strip_tags($this->upload->display_errors('', ''))); continue; } $uploadData = $this->upload->data(); // Optimize image: resize to max 1080px and compress $imageConfig = array( 'image_library' => 'gd2', 'source_image' => $uploadData['full_path'], 'maintain_ratio' => TRUE, 'quality' => '70%', // Better compression 'master_dim' => 'auto', // Auto-detect longest side 'width' => 1080, 'height' => 1080, ); $this->image_lib->clear(); $this->image_lib->initialize($imageConfig); // Resize if image is larger than 1080px on any side if ($uploadData['image_width'] > 1080 || $uploadData['image_height'] > 1080) { $this->image_lib->resize(); } else { // Still reprocess for compression even if size is OK $this->image_lib->resize(); } $savedImages[] = array( 'filename' => 'uploads/diary/' . $user_id . '/' . $uploadData['file_name'], ); } if (!empty($savedImages)) { $this->note->add_diary_images($note_id, $savedImages); } if (!empty($errors)) { return implode(' ', $errors); } return null; } /* Displays all notes in a list */ public function index() { $this->load->model('note'); $filters = array( 'search' => $this->input->get('q', TRUE), 'category' => $this->input->get('category', TRUE), 'date_from' => $this->input->get('date_from', TRUE), 'date_to' => $this->input->get('date_to', TRUE) ); $data['filters'] = $filters; $data['categories'] = $this->note->list_categories(); $data['notes'] = $this->note->list_all(null, $filters); $data['public_station_diary_enabled'] = $this->is_public_station_diary_enabled(); $data['public_diary_url'] = site_url('station-diary/' . rawurlencode((string)$this->session->userdata('user_callsign'))); // Check if there are any Station Diary entries $diary_filter = array('category' => 'Station Diary'); $diary_entries = $this->note->list_all(null, $diary_filter); $data['has_diary_entries'] = $diary_entries->num_rows() > 0; $data['page_title'] = "Notes"; $this->load->view('interface_assets/header', $data); $this->load->view('notes/main'); $this->load->view('interface_assets/footer'); } /* Provides function for adding notes to the system. */ function add() { $this->load->model('note'); $this->load->model('logbooks_model'); $data['categories'] = $this->note->list_categories(); $data['public_station_diary_enabled'] = $this->is_public_station_diary_enabled(); $data['user_logbooks'] = $this->logbooks_model->show_all(); $this->load->library('form_validation'); $this->form_validation->set_rules('title', 'Note Title', 'required'); $this->form_validation->set_rules('content', 'Content', 'required'); if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Add Notes"; $this->load->view('interface_assets/header', $data); $this->load->view('notes/add'); $this->load->view('interface_assets/footer'); } else { $note_id = $this->note->add(); $upload_error = $this->handle_diary_images_upload($note_id); if (!empty($upload_error)) { $this->session->set_flashdata('notice', $upload_error); } redirect('notes'); } } /* Quick add note via HTMX (for Station Diary modal) */ function quick_add() { $this->load->model('note'); $this->load->library('form_validation'); $this->form_validation->set_rules('title', 'Note Title', 'required'); $this->form_validation->set_rules('content', 'Content', 'required'); $this->form_validation->set_rules('category', 'Category', 'required'); if ($this->form_validation->run() == FALSE) { echo '
' . validation_errors() . '
'; } else { $note_id = $this->note->add(); $upload_error = $this->handle_diary_images_upload($note_id); $message = 'Note saved successfully! View all notes'; if (!empty($upload_error)) { $message .= '
' . $upload_error . ''; } echo '
' . $message . '
'; // Reset form via JavaScript echo ''; } } /* View Notes */ function view($id) { $this->load->model('note'); $data['note'] = $this->note->view($id); $data['diary_images'] = $this->note->get_diary_images(array((int)$id)); // Display $data['page_title'] = "Note"; $this->load->view('interface_assets/header', $data); $this->load->view('notes/view'); $this->load->view('interface_assets/footer'); } /* Edit Notes */ function edit($id) { $this->load->model('note'); $this->load->model('logbooks_model'); $data['id'] = $id; $data['note'] = $this->note->view($id); $data['categories'] = $this->note->list_categories(); $data['diary_images'] = $this->note->get_diary_images(array((int)$id)); $data['public_station_diary_enabled'] = $this->is_public_station_diary_enabled(); $data['user_logbooks'] = $this->logbooks_model->show_all(); $this->load->library('form_validation'); $this->form_validation->set_rules('title', 'Note Title', 'required'); $this->form_validation->set_rules('content', 'Content', 'required'); if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Edit Note"; $this->load->view('interface_assets/header', $data); $this->load->view('notes/edit'); $this->load->view('interface_assets/footer'); } else { $note_id = $this->note->edit(); $upload_error = $this->handle_diary_images_upload($note_id); if (!empty($upload_error)) { $this->session->set_flashdata('notice', $upload_error); } redirect('notes'); } } /* Delete Note */ function delete() { // Enforce POST for destructive action if (strtolower($this->input->method()) !== 'post') { $this->session->set_flashdata('notice', $this->lang->line('general_word_warning') . ': invalid request method.'); redirect('notes'); return; } $id = $this->input->post('id', TRUE); if (empty($id)) { $this->session->set_flashdata('notice', $this->lang->line('general_word_warning') . ': missing note id.'); redirect('notes'); return; } $this->load->model('note'); $this->note->delete($id); $this->session->set_flashdata('notice', $this->lang->line('admin_delete') ?: 'Deleted'); redirect('notes'); } /* Delete Diary Image (AJAX) */ function delete_diary_image() { // Enforce POST for destructive action if (strtolower($this->input->method()) !== 'post') { header('Content-Type: application/json'); echo json_encode(array('success' => false, 'message' => 'Invalid request method')); return; } $image_id = $this->input->post('image_id', TRUE); if (empty($image_id)) { header('Content-Type: application/json'); echo json_encode(array('success' => false, 'message' => 'Missing image ID')); return; } $this->load->model('note'); $user_id = $this->session->userdata('user_id'); $result = $this->note->delete_diary_image_by_id($image_id, $user_id); header('Content-Type: application/json'); if ($result) { echo json_encode(array('success' => true, 'message' => 'Image deleted successfully')); } else { echo json_encode(array('success' => false, 'message' => 'Image not found or permission denied')); } } /* Print Station Diary */ public function station_diary() { $this->load->model('note'); $filters = array( 'category' => 'Station Diary' ); $data['diary_entries'] = $this->note->list_all(null, $filters); $data['page_title'] = "Station Diary"; // Load diary images for all entries $entry_ids = array(); foreach ($data['diary_entries']->result() as $entry) { $entry_ids[] = (int)$entry->id; } if (!empty($entry_ids)) { $data['diary_images'] = $this->note->get_diary_images($entry_ids); } else { $data['diary_images'] = array(); } // Load without header/footer for print formatting $this->load->view('notes/station_diary_print', $data); } /* Delete/Merge Category */ function delete_category() { if (strtolower($this->input->method()) !== 'post') { $this->session->set_flashdata('notice', $this->lang->line('general_word_warning') . ': invalid request method.'); redirect('notes'); return; } $source = trim($this->input->post('source_category', TRUE)); $target = trim($this->input->post('target_category', TRUE)); if ($source === '') { $this->session->set_flashdata('notice', $this->lang->line('general_word_warning') . ': missing source category.'); redirect('notes'); return; } if ($target === '') { $target = 'General'; } if ($source === $target) { $this->session->set_flashdata('notice', $this->lang->line('general_word_warning') . ': choose a different target category.'); redirect('notes'); return; } $this->load->model('note'); $affected = $this->note->replace_category($source, $target); $this->session->set_flashdata('notice', sprintf('%s → %s (%d)', $source, $target, $affected)); redirect('notes'); } public function update_image_caption() { header('Content-Type: application/json'); $this->load->model('user_model'); if (!$this->user_model->authorize(2)) { echo json_encode(array('success' => false, 'message' => 'Unauthorized')); return; } $imageId = (int)$this->input->post('image_id'); $caption = trim($this->input->post('caption', TRUE)); if ($imageId <= 0) { echo json_encode(array('success' => false, 'message' => 'Invalid image ID')); return; } $this->load->model('note'); // Verify ownership through the diary entry $this->db->select('diary_images.id, diary_images.diary_id'); $this->db->from('diary_images'); $this->db->join('notes', 'notes.id = diary_images.diary_id'); $this->db->where('diary_images.id', $imageId); $this->db->where('notes.user_id', (int)$this->session->userdata('user_id')); $query = $this->db->get(); if ($query->num_rows() === 0) { echo json_encode(array('success' => false, 'message' => 'Image not found or access denied')); return; } $imageRow = $query->row(); // Update caption $this->db->where('id', $imageId); $this->db->update('diary_images', array('caption' => $caption)); $this->note->invalidate_public_diary_cache_for_note((int)$imageRow->diary_id, (int)$this->session->userdata('user_id')); echo json_encode(array('success' => true)); } }