You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

414 lines
29 KiB

<?php
if (file_exists(__DIR__."/../../pp-config.php")) {
if (file_exists(__DIR__.'/../../maintenance.lock')) {
if (file_exists(__DIR__.'/../../pp-include/pp-maintenance.php')) {
}else{
die('System is under maintenance. Please try again later.');
}
exit();
}else{
if (file_exists(__DIR__.'/../../pp-include/pp-controller.php')) {
if (file_exists(__DIR__.'/../../pp-include/pp-view.php')) {
}else{
echo 'System is under maintenance. Please try again later.';
exit();
}
}else{
echo 'System is under maintenance. Please try again later.';
exit();
}
if (file_exists(__DIR__.'/../../pp-include/pp-model.php')) {
include(__DIR__."/../../pp-include/pp-model.php");
}else{
echo 'System is under maintenance. Please try again later.';
exit();
}
}
}else{
echo 'System is under maintenance. Please try again later.';
exit();
}
if (!defined('pp_allowed_access')) {
die('Direct access not allowed');
}
if(isset($global_user_login) && $global_user_login == true){
?>
<style>
.plugin-card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
border-radius: 0.5rem;
overflow: hidden;
}
.plugin-card:hover {
transform: translateY(-2px);
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.1);
}
.plugin-icon {
display: flex;
align-items: center;
justify-content: center;
border-radius: 0.5rem;
font-size: 1.5rem;
}
.plugin-icon img{
height: 40px;
}
.status-badge {
font-size: 0.65rem;
letter-spacing: 0.5px;
padding: 3px 6px;
}
.nav-pills .nav-link.active {
}
.nav-pills .nav-link {
color: #495057;
font-weight: 500;
}
.tab-content {
background: #fff;
border-radius: 0 0.5rem 0.5rem 0.5rem;
}
.search-box {
position: relative;
}
.search-box .form-control {
padding-left: 2.5rem;
border-radius: 2rem;
}
.search-box .bi {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: #6c757d;
}
.plugin-actions .btn {
padding: 0.25rem 0.5rem;
font-size: 0.8rem;
}
</style>
<div class="row">
<div class="col-lg-12 mx-auto">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-0 pb-0">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h4 mb-0">
<i class="bi bi-plug me-2 text-primary"></i>Plugin Manager
</h1>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#add-new-plugins">
<i class="bi bi-plus-lg me-1"></i> Add New
</button>
</div>
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="pills-installed-tab" data-bs-toggle="pill" data-bs-target="#pills-installed" type="button" role="tab">
<i class="bi bi-check-circle me-1"></i> Installed (<span class="installed-count">0</span>)
</button>
</li>
</ul>
</div>
<span class="response-action"></span>
<div class="card-body pt-0">
<div class="tab-content" id="pills-tabContent">
<!-- Installed Plugins Tab -->
<div class="tab-pane fade show active" id="pills-installed" role="tabpanel">
<div class="row mb-4">
<div class="col-md-6">
<div class="search-box">
<i class="bi bi-search"></i>
<input type="text" class="form-control" id="pluginSearch" onkeyup="filterPlugins('all')"placeholder="Search installed plugins...">
</div>
</div>
<div class="col-md-6">
<div class="d-flex justify-content-end">
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown">
<i class="bi bi-funnel me-1"></i> Filter
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="#" onclick="filterPlugins('all')">All Plugins</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" onclick="filterPlugins('active')">Active Only</a></li>
<li><a class="dropdown-item" href="#" onclick="filterPlugins('inactive')">Inactive Only</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="row g-4">
<?php
$baseDir = __DIR__.'/../../pp-content/plugins/';
$mainFolders = array_filter(scandir($baseDir), function($item) use ($baseDir) {
return $item !== '.' && $item !== '..' && is_dir($baseDir . DIRECTORY_SEPARATOR . $item);
});
$foundPlugins = false;
$installed_count = 0;
foreach ($mainFolders as $mainFolder) {
$pluginBasePath = $baseDir . DIRECTORY_SEPARATOR . $mainFolder;
$pluginFolders = array_filter(scandir($pluginBasePath), function($item) use ($pluginBasePath) {
return $item !== '.' && $item !== '..' && is_dir($pluginBasePath . DIRECTORY_SEPARATOR . $item);
});
$rand_db = 0;
foreach ($pluginFolders as $pluginFolder) {
$rand_db = rand()+$rand_db;
$mainLocation = $pluginBasePath . DIRECTORY_SEPARATOR . $pluginFolder. DIRECTORY_SEPARATOR;
$mainFile = $pluginBasePath . DIRECTORY_SEPARATOR . $pluginFolder . DIRECTORY_SEPARATOR . $pluginFolder . '-class.php';
if (file_exists($mainFile)) {
$foundPlugins = true;
$pluginInfo = parsePluginHeader($mainFile);
$response_plugin = json_decode(getData($db_prefix.'plugins', 'WHERE plugin_slug="'.$pluginFolder.'" AND status="active"'), true);
$plugin_rand = rand();
$installed_count = $installed_count+1;
?>
<!-- Plugin Card 1 -->
<div class="col-md-6 col-lg-4 plugin-items <?php if($response_plugin['status'] == true){echo "active";}else{echo "inactive";}?>plugins">
<div class="plugin-card card h-100 border">
<div class="card-body">
<div class="d-flex align-items-start mb-3">
<div class="plugin-icon bg-primary bg-opacity-10 text-primary me-3">
<img src="https://<?php echo $_SERVER['HTTP_HOST']?>/pp-content/plugins/<?php echo $mainFolder.'/'.$pluginFolder?>/assets/icon.png" loading="lazy" alt="Image Description" width="auto" height="auto">
</div>
<div class="flex-grow-1">
<h5 class="mb-1"><?php echo htmlspecialchars($pluginInfo['Plugin Name'] ?? '')?></h5>
<p class="text-primary small mb-2" onclick="location.href='<?php echo htmlspecialchars($pluginInfo['Author URI'] ?? '')?>'" style="cursor: pointer;">v<?php echo htmlspecialchars($pluginInfo['Version'] ?? '')?> by <?php echo htmlspecialchars($pluginInfo['Author'] ?? '')?></p>
<?php
if($response_plugin['status'] == true){
?>
<span class="badge bg-success status-badge me-1">Active</span>
<?php
}else{
?>
<span class="badge bg-danger status-badge me-1">Inactive</span>
<?php
}
?>
</div>
</div>
<p class="small text-muted mb-3"><?php echo htmlspecialchars($pluginInfo['Description'] ?? '')?></p>
<div class="plugin-actions d-flex justify-content-between border-top pt-3">
<button class="btn btn-outline-secondary btn-sm" data-bs-toggle="modal" data-bs-target="#pluginDetailsModal<?php echo $plugin_rand?>">
<i class="bi bi-info-circle me-1"></i> Details
</button>
<?php
if($response_plugin['status'] == true){
?>
<button class="btn btn-outline-danger btn-sm btn-deactivate<?php echo $plugin_rand?>" onclick="pluginhit('btn-deactivate<?php echo $plugin_rand?>', 'deactivate', '<?php echo $mainFolder?>', '<?php echo $pluginFolder?>', 'pluginDetailsModal<?php echo $plugin_rand?>')">
<i class="bi bi-power me-1"></i> Deactivate
</button>
<?php
}else{
?>
<button class="btn btn-outline-success btn-sm btn-activate<?php echo $plugin_rand?>" onclick="pluginhit('btn-activate<?php echo $plugin_rand?>', 'activate', '<?php echo $mainFolder?>', '<?php echo $pluginFolder?>', 'pluginDetailsModal<?php echo $plugin_rand?>')">
<i class="bi bi-power me-1"></i> Activate
</button>
<button class="btn btn-outline-dark btn-sm btn-delete<?php echo $plugin_rand?>" onclick="pluginhit('btn-delete<?php echo $plugin_rand?>', 'delete', '<?php echo $mainFolder?>', '<?php echo $pluginFolder?>', 'pluginDetailsModal<?php echo $plugin_rand?>')">
<i class="bi bi-trash3 me-1"></i> Delete
</button>
<?php
}
?>
</div>
</div>
</div>
</div>
<!-- Plugin Details Modal -->
<div class="modal fade" id="pluginDetailsModal<?php echo $plugin_rand?>" tabindex="-1" aria-labelledby="pluginDetailsModalLabel<?php echo $plugin_rand?>" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pluginDetailsModalLabel<?php echo $plugin_rand?>">Plugin Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<h4><?php echo htmlspecialchars($pluginInfo['Plugin Name'] ?? '')?></h4>
<?php
if (file_exists($mainLocation.'readme.txt')) {
$content = file_get_contents($mainLocation.'readme.txt');
$sections = parse_readme_sections($content);
$pluginHeader = parse_readme_header($content);
$tags = [];
if (!empty($pluginHeader['tags'])) {
$tags = array_map('trim', explode(',', $pluginHeader['tags']));
}
?>
<p class="text-muted"><?php echo htmlspecialchars($pluginInfo['Description'] ?? '')?></p>
<div class="d-flex flex-wrap gap-2 mb-4">
<?php foreach ($tags as $tag): ?>
<span class="badge bg-primary"><?php echo htmlspecialchars($tag); ?></span>
<?php endforeach; ?>
</div>
<div class="mb-4">
<h5>Description</h5>
<p><?php echo nl2br(htmlspecialchars($sections['description'] ?? 'N/A')); ?></p>
<h5 class="mt-4">Changelog</h5>
<?php
$changelogData = parse_readme_changelog($sections['changelog'] ?? '');
?>
<div class="accordion" id="changelogAccordion">
<?php
$index = 0;
foreach ($changelogData as $version => $items):
$isFirst = ($index === 0);
$collapseId = 'changelog' . $index;
?>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button <?php echo $isFirst ? '' : 'collapsed'; ?>" type="button" data-bs-toggle="collapse" data-bs-target="#<?php echo $collapseId; ?>">
Version <?php echo htmlspecialchars($version); ?><?php echo $isFirst ? ' (Current)' : ''; ?>
</button>
</h2>
<div id="<?php echo $collapseId; ?>" class="accordion-collapse collapse <?php echo $isFirst ? 'show' : ''; ?>" data-bs-parent="#changelogAccordion">
<div class="accordion-body small">
<ul>
<?php foreach ($items as $item): ?>
<li><?php echo htmlspecialchars($item); ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
<?php
$index++;
endforeach;
?>
</div>
</div>
<?php
}
?>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<?php
if($response_plugin['status'] == true){
?>
<button type="button" class="btn btn-danger btn-deactivate<?php echo $plugin_rand?>-popup" onclick="pluginhit('btn-deactivate<?php echo $plugin_rand?>-popup', 'deactivate', '<?php echo $mainFolder?>', '<?php echo $pluginFolder?>', 'pluginDetailsModal<?php echo $plugin_rand?>')">Deactivate</button>
<?php
}else{
?>
<button type="button" class="btn btn-primary btn-activate<?php echo $plugin_rand?>-popup" onclick="pluginhit('btn-activate<?php echo $plugin_rand?>-popup', 'activate', '<?php echo $mainFolder?>', '<?php echo $pluginFolder?>', 'pluginDetailsModal<?php echo $plugin_rand?>')">Activate</button>
<?php
}
?>
</div>
</div>
</div>
</div>
<?php
}
}
}
if (!$foundPlugins) {
?>
<div class="col-md-12 col-lg-12">
<div class="alert alert-danger"><i class="bi bi-info-circle-fill me-2"></i> No plugins available</div>
</div>
<?php
}
?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function initialize(){
document.querySelector(".installed-count").innerHTML = "<?php echo $installed_count?>";
}
initialize();
function filterPlugins(type) {
currentFilter = type;
const search = document.getElementById('pluginSearch').value.toLowerCase();
document.querySelectorAll('.plugin-items').forEach(el => {
const name = el.querySelector('h5')?.textContent.toLowerCase() || '';
const matchesType = (type === "all") || el.classList.contains(type + "plugins");
const matchesSearch = name.includes(search);
if (matchesType && matchesSearch) {
el.style.display = 'block';
} else {
el.style.display = 'none';
}
});
}
function pluginhit(btn, type, mainfolder, pluginfolder, model){
var btn_value = document.querySelector("."+btn).innerHTML;
$("."+btn).html('<div class="spinner-border spinner-border-sm" role="status"> <span class="visually-hidden">Loading...</span> </div>');
$("."+btn).prop("disabled", true);
$.ajax
({
type: "POST",
url: "https://<?php echo $_SERVER['HTTP_HOST']?>/admin/plugin-manager",
data: { "action": "pp_plugin_manager", "type": type, "mainfolder": mainfolder, "pluginfolder": pluginfolder},
success: function (data) {
console.log(data);
$("."+btn).prop("disabled", false);
$("."+btn).html(btn_value);
$('#'+model).modal('hide');
var dedata = JSON.parse(data);
if(dedata.status == "false"){
document.querySelector(".response-action").innerHTML = '<div class="alert alert-danger" style="margin-top:10px;margin-bottom:10px"> <i class="fa fa-info-circle me-2"></i> '+dedata.message+'</div>';
}else{
$('#'+model).modal('hide');
load_content('Plugin','plugin-manager','nav-btn-plugin')
}
}
});
}
</script>
<?php
}
?>