diff --git a/emailMarketing/.DS_Store b/emailMarketing/.DS_Store
deleted file mode 100644
index 742482470..000000000
Binary files a/emailMarketing/.DS_Store and /dev/null differ
diff --git a/emailMarketing/__init__.py b/emailMarketing/__init__.py
deleted file mode 100644
index d33aad86a..000000000
--- a/emailMarketing/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-default_app_config = 'emailMarketing.apps.EmailmarketingConfig'
\ No newline at end of file
diff --git a/emailMarketing/admin.py b/emailMarketing/admin.py
deleted file mode 100644
index 4c33e0ec3..000000000
--- a/emailMarketing/admin.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from django.contrib import admin
-
-# Register your models here.
diff --git a/emailMarketing/apps.py b/emailMarketing/apps.py
deleted file mode 100644
index 6de896393..000000000
--- a/emailMarketing/apps.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from django.apps import AppConfig
-
-
-class EmailmarketingConfig(AppConfig):
- name = 'emailMarketing'
- def ready(self):
- from . import signals
diff --git a/emailMarketing/emACL.py b/emailMarketing/emACL.py
deleted file mode 100644
index e68571c8f..000000000
--- a/emailMarketing/emACL.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from .models import EmailMarketing, EmailTemplate, SMTPHosts, EmailLists, EmailJobs
-from websiteFunctions.models import Websites
-
-class emACL:
-
- @staticmethod
- def checkIfEMEnabled(userName):
- try:
- user = EmailMarketing.objects.get(userName=userName)
- return 0
- except:
- return 1
-
- @staticmethod
- def getEmailsLists(domain):
- website = Websites.objects.get(domain=domain)
- emailLists = website.emaillists_set.all()
- listNames = []
-
- for items in emailLists:
- listNames.append(items.listName)
-
- return listNames
-
- @staticmethod
- def allTemplates(currentACL, admin):
- if currentACL['admin'] == 1:
- allTemplates = EmailTemplate.objects.all()
- else:
- allTemplates = admin.emailtemplate_set.all()
-
- templateNames = []
- for items in allTemplates:
- templateNames.append(items.name)
- return templateNames
-
- @staticmethod
- def allSMTPHosts(currentACL, admin):
- if currentACL['admin'] == 1:
- allHosts = SMTPHosts.objects.all()
- else:
- allHosts = admin.smtphosts_set.all()
- hostNames = []
-
- for items in allHosts:
- hostNames.append(items.host)
-
- return hostNames
-
- @staticmethod
- def allEmailsLists(currentACL, admin):
- listNames = []
- emailLists = EmailLists.objects.all()
-
- if currentACL['admin'] == 1:
- for items in emailLists:
- listNames.append(items.listName)
- else:
- for items in emailLists:
- if items.owner.admin == admin:
- listNames.append(items.listName)
-
- return listNames
-
-
-
diff --git a/emailMarketing/emailMarketing.py b/emailMarketing/emailMarketing.py
deleted file mode 100644
index 3ac749ad6..000000000
--- a/emailMarketing/emailMarketing.py
+++ /dev/null
@@ -1,427 +0,0 @@
-#!/usr/local/CyberCP/bin/python
-
-import os
-import time
-import csv
-import re
-import plogical.CyberCPLogFileWriter as logging
-from .models import EmailLists, EmailsInList, EmailTemplate, EmailJobs, SMTPHosts, ValidationLog
-from plogical.backupSchedule import backupSchedule
-from websiteFunctions.models import Websites
-import threading as multi
-import socket, smtplib
-import DNS
-from random import randint
-from plogical.processUtilities import ProcessUtilities
-
-class emailMarketing(multi.Thread):
- def __init__(self, function, extraArgs):
- multi.Thread.__init__(self)
- self.function = function
- self.extraArgs = extraArgs
-
- def run(self):
- try:
- if self.function == 'createEmailList':
- self.createEmailList()
- elif self.function == 'verificationJob':
- self.verificationJob()
- elif self.function == 'startEmailJob':
- self.startEmailJob()
- except BaseException as msg:
- logging.CyberCPLogFileWriter.writeToFile(str(msg) + ' [emailMarketing.run]')
-
- def createEmailList(self):
- try:
- website = Websites.objects.get(domain=self.extraArgs['domain'])
- try:
- newList = EmailLists(owner=website, listName=self.extraArgs['listName'], dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y"))
- newList.save()
- except:
- newList = EmailLists.objects.get(listName=self.extraArgs['listName'])
-
- counter = 0
-
- if self.extraArgs['path'].endswith('.csv'):
- with open(self.extraArgs['path'], 'r') as emailsList:
- data = csv.reader(emailsList, delimiter=',')
- for items in data:
- try:
- for value in items:
- if re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', value) != None:
- try:
- getEmail = EmailsInList.objects.get(owner=newList, email=value)
- except:
- try:
- newEmail = EmailsInList(owner=newList, email=value,
- verificationStatus='NOT CHECKED',
- dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y"))
- newEmail.save()
- except:
- pass
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(counter) + ' emails read.')
- counter = counter + 1
- except BaseException as msg:
- logging.CyberCPLogFileWriter.writeToFile('%s. [createEmailList]' % (str(msg)))
- continue
- elif self.extraArgs['path'].endswith('.txt'):
- with open(self.extraArgs['path'], 'r') as emailsList:
- emails = emailsList.readline()
- while emails:
- email = emails.strip('\n')
- if re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', email) != None:
- try:
- getEmail = EmailsInList.objects.get(owner=newList, email=email)
- except BaseException as msg:
- newEmail = EmailsInList(owner=newList, email=email, verificationStatus='NOT CHECKED',
- dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y"))
- newEmail.save()
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],str(counter) + ' emails read.')
- counter = counter + 1
- emails = emailsList.readline()
-
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(counter) + 'Successfully read all emails. [200]')
- except BaseException as msg:
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(msg) +'. [404]')
- return 0
-
- def findNextIP(self):
- try:
- if self.delayData['rotation'] == 'Disable':
- return None
- elif self.delayData['rotation'] == 'IPv4':
- if self.delayData['ipv4'].find(',') == -1:
- return self.delayData['ipv4']
- else:
- ipv4s = self.delayData['ipv4'].split(',')
-
- if self.currentIP == '':
- return ipv4s[0]
- else:
- returnCheck = 0
-
- for items in ipv4s:
- if returnCheck == 1:
- return items
- if items == self.currentIP:
- returnCheck = 1
-
- return ipv4s[0]
- else:
- if self.delayData['ipv6'].find(',') == -1:
- return self.delayData['ipv6']
- else:
- ipv6 = self.delayData['ipv6'].split(',')
-
- if self.currentIP == '':
- return ipv6[0]
- else:
- returnCheck = 0
-
- for items in ipv6:
- if returnCheck == 1:
- return items
- if items == self.currentIP:
- returnCheck = 1
- return ipv6[0]
- except BaseException as msg:
- logging.CyberCPLogFileWriter.writeToFile(str(msg))
- return None
-
- def verificationJob(self):
- try:
-
- verificationList = EmailLists.objects.get(listName=self.extraArgs['listName'])
- domain = verificationList.owner.domain
-
- if not os.path.exists('/home/cyberpanel/' + domain):
- os.mkdir('/home/cyberpanel/' + domain)
-
- tempStatusPath = '/home/cyberpanel/' + domain + "/" + self.extraArgs['listName']
- logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Starting verification job..')
-
- counter = 1
- counterGlobal = 0
-
- allEmailsInList = verificationList.emailsinlist_set.all()
-
- configureVerifyPath = '/home/cyberpanel/configureVerify'
- finalPath = '%s/%s' % (configureVerifyPath, domain)
-
-
- import json
- if os.path.exists(finalPath):
- self.delayData = json.loads(open(finalPath, 'r').read())
-
- self.currentIP = ''
-
- ValidationLog(owner=verificationList, status=backupSchedule.INFO, message='Starting email verification..').save()
-
- for items in allEmailsInList:
- if items.verificationStatus != 'Verified':
- try:
-
- email = items.email
- self.currentEmail = email
- domainName = email.split('@')[1]
- records = DNS.dnslookup(domainName, 'MX', 15)
-
- counterGlobal = counterGlobal + 1
-
- for mxRecord in records:
-
- # Get local server hostname
- host = socket.gethostname()
-
- ## Only fetching smtp object
-
- if os.path.exists(finalPath):
- try:
- delay = self.delayData['delay']
- if delay == 'Enable':
- if counterGlobal == int(self.delayData['delayAfter']):
- ValidationLog(owner=verificationList, status=backupSchedule.INFO,
- message='Sleeping for %s seconds...' % (self.delayData['delayTime'])).save()
-
- time.sleep(int(self.delayData['delayTime']))
- counterGlobal = 0
- self.currentIP = self.findNextIP()
-
- ValidationLog(owner=verificationList, status=backupSchedule.INFO,
- message='IP being used for validation until next sleep: %s.' % (str(self.currentIP))).save()
-
- if self.currentIP == None:
- server = smtplib.SMTP(timeout=10)
- else:
- server = smtplib.SMTP(self.currentIP, timeout=10)
- else:
-
- if self.currentIP == '':
- self.currentIP = self.findNextIP()
- ValidationLog(owner=verificationList, status=backupSchedule.INFO,
- message='IP being used for validation until next sleep: %s.' % (
- str(self.currentIP))).save()
-
- if self.currentIP == None:
- server = smtplib.SMTP(timeout=10)
- else:
- server = smtplib.SMTP(self.currentIP, timeout=10)
- else:
- logging.CyberCPLogFileWriter.writeToFile(
- 'Delay not configured..')
-
- ValidationLog(owner=verificationList, status=backupSchedule.INFO,
- message='Delay not configured..').save()
-
- server = smtplib.SMTP(timeout=10)
- except BaseException as msg:
-
- ValidationLog(owner=verificationList, status=backupSchedule.ERROR,
- message='Delay not configured. Error message: %s' % (str(msg))).save()
-
- server = smtplib.SMTP(timeout=10)
- else:
- server = smtplib.SMTP(timeout=10)
-
- ###
-
- server.set_debuglevel(0)
-
- # SMTP Conversation
- server.connect(mxRecord[1])
- server.helo(host)
- server.mail('host' + "@" + host)
- code, message = server.rcpt(str(email))
- server.quit()
-
- # Assume 250 as Success
- if code == 250:
- items.verificationStatus = 'Verified'
- items.save()
- break
- else:
- ValidationLog(owner=verificationList, status=backupSchedule.ERROR,
- message='Failed to verify %s. Error message %s' % (email, message.decode())).save()
- items.verificationStatus = 'Verification Failed'
- items.save()
-
- logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(counter) + ' emails verified so far..')
- counter = counter + 1
- except BaseException as msg:
- items.verificationStatus = 'Verification Failed'
- items.save()
- counter = counter + 1
- ValidationLog(owner=verificationList, status=backupSchedule.ERROR,
- message='Failed to verify %s. Error message %s' % (
- self.currentEmail , str(msg))).save()
-
-
- verificationList.notVerified = verificationList.emailsinlist_set.filter(verificationStatus='Verification Failed').count()
- verificationList.verified = verificationList.emailsinlist_set.filter(verificationStatus='Verified').count()
- verificationList.save()
-
- ValidationLog(owner=verificationList, status=backupSchedule.ERROR, message=str(counter) + ' emails successfully verified. [200]').save()
-
- logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(counter) + ' emails successfully verified. [200]')
- except BaseException as msg:
- verificationList = EmailLists.objects.get(listName=self.extraArgs['listName'])
- domain = verificationList.owner.domain
- tempStatusPath = '/home/cyberpanel/' + domain + "/" + self.extraArgs['listName']
- logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(msg) +'. [404]')
- logging.CyberCPLogFileWriter.writeToFile(str(msg))
- return 0
-
- def setupSMTPConnection(self):
- try:
- if self.extraArgs['host'] == 'localhost':
- self.smtpServer = smtplib.SMTP('127.0.0.1')
- return 1
- else:
- self.verifyHost = SMTPHosts.objects.get(host=self.extraArgs['host'])
- self.smtpServer = smtplib.SMTP(str(self.verifyHost.host), int(self.verifyHost.port))
-
- if int(self.verifyHost.port) == 587:
- self.smtpServer.starttls()
-
- self.smtpServer.login(str(self.verifyHost.userName), str(self.verifyHost.password))
- return 1
- except smtplib.SMTPHeloError:
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
- 'The server didnt reply properly to the HELO greeting.')
- return 0
- except smtplib.SMTPAuthenticationError:
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
- 'Username and password combination not accepted.')
- return 0
- except smtplib.SMTPException:
- logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
- 'No suitable authentication method was found.')
- return 0
-
- def startEmailJob(self):
- try:
-
- if self.setupSMTPConnection() == 0:
- logging.CyberCPLogFileWriter.writeToFile('SMTP Connection failed. [301]')
- return 0
-
- emailList = EmailLists.objects.get(listName=self.extraArgs['listName'])
- allEmails = emailList.emailsinlist_set.all()
- emailMessage = EmailTemplate.objects.get(name=self.extraArgs['selectedTemplate'])
-
- totalEmails = allEmails.count()
- sent = 0
- failed = 0
-
- ipFile = "/etc/cyberpanel/machineIP"
- f = open(ipFile)
- ipData = f.read()
- ipAddress = ipData.split('\n', 1)[0]
-
- ## Compose Message
- from email.mime.multipart import MIMEMultipart
- from email.mime.text import MIMEText
- import re
-
- tempPath = "/home/cyberpanel/" + str(randint(1000, 9999))
-
- emailJob = EmailJobs(owner=emailMessage, date=time.strftime("%I-%M-%S-%a-%b-%Y"),
- host=self.extraArgs['host'], totalEmails=totalEmails,
- sent=sent, failed=failed
- )
- emailJob.save()
-
- for items in allEmails:
- try:
- message = MIMEMultipart('alternative')
- message['Subject'] = emailMessage.subject
- message['From'] = emailMessage.fromEmail
- message['reply-to'] = emailMessage.replyTo
-
- if (items.verificationStatus == 'Verified' or self.extraArgs[
- 'verificationCheck']) and not items.verificationStatus == 'REMOVED':
- try:
- port = ProcessUtilities.fetchCurrentPort()
- removalLink = "https:\/\/" + ipAddress + ":%s\/emailMarketing\/remove\/" % (port) + self.extraArgs[
- 'listName'] + "\/" + items.email
- messageText = emailMessage.emailMessage.encode('utf-8', 'replace')
- message['To'] = items.email
-
- if re.search(b'
-
- Email Marketing
- Utility
- Email Marketing plugin for CyberPanel.
- 1.0.1
-
\ No newline at end of file
diff --git a/emailMarketing/migrations/__init__.py b/emailMarketing/migrations/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/emailMarketing/models.py b/emailMarketing/models.py
deleted file mode 100644
index b352f2549..000000000
--- a/emailMarketing/models.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from django.db import models
-from websiteFunctions.models import Websites
-from loginSystem.models import Administrator
-
-# Create your models here.
-
-class EmailMarketing(models.Model):
- userName = models.CharField(max_length=50, unique=True)
-
-class EmailLists(models.Model):
- owner = models.ForeignKey(Websites, on_delete=models.PROTECT)
- listName = models.CharField(max_length=50, unique=True)
- dateCreated = models.CharField(max_length=200)
- verified = models.IntegerField(default=0)
- notVerified = models.IntegerField(default=0)
-
-class EmailsInList(models.Model):
- owner = models.ForeignKey(EmailLists, on_delete=models.CASCADE)
- email = models.CharField(max_length=50)
- firstName = models.CharField(max_length=20, default='')
- lastName = models.CharField(max_length=20, default='')
- verificationStatus = models.CharField(max_length=100)
- dateCreated = models.CharField(max_length=200)
-
-class SMTPHosts(models.Model):
- owner = models.ForeignKey(Administrator, on_delete=models.CASCADE)
- host = models.CharField(max_length=150, unique= True)
- port = models.CharField(max_length=10)
- userName = models.CharField(max_length=200)
- password = models.CharField(max_length=200)
-
-class EmailTemplate(models.Model):
- owner = models.ForeignKey(Administrator, on_delete=models.CASCADE)
- name = models.CharField(unique=True, max_length=100)
- subject = models.CharField(max_length=1000)
- fromName = models.CharField(max_length=100)
- fromEmail = models.CharField(max_length=150)
- replyTo = models.CharField(max_length=150)
- emailMessage = models.TextField(max_length=65532)
-
-class EmailJobs(models.Model):
- owner = models.ForeignKey(EmailTemplate, on_delete=models.CASCADE)
- date = models.CharField(max_length=200)
- host = models.CharField(max_length=1000)
- totalEmails = models.IntegerField()
- sent = models.IntegerField()
- failed = models.IntegerField()
-
-class ValidationLog(models.Model):
- owner = models.ForeignKey(EmailLists, on_delete=models.CASCADE)
- status = models.IntegerField()
- message = models.TextField()
-
diff --git a/emailMarketing/signals.py b/emailMarketing/signals.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/emailMarketing/static/emailMarketing/checklist.png b/emailMarketing/static/emailMarketing/checklist.png
deleted file mode 100644
index 5236aa0a8..000000000
Binary files a/emailMarketing/static/emailMarketing/checklist.png and /dev/null differ
diff --git a/emailMarketing/static/emailMarketing/compose.png b/emailMarketing/static/emailMarketing/compose.png
deleted file mode 100644
index 4e786da4d..000000000
Binary files a/emailMarketing/static/emailMarketing/compose.png and /dev/null differ
diff --git a/emailMarketing/static/emailMarketing/emailMarketing.js b/emailMarketing/static/emailMarketing/emailMarketing.js
deleted file mode 100644
index 69ed07493..000000000
--- a/emailMarketing/static/emailMarketing/emailMarketing.js
+++ /dev/null
@@ -1,1468 +0,0 @@
-/**
- * Created by usman on 8/1/17.
- */
-
-var emailListURL = "/emailMarketing/" + $("#domainNamePage").text() + "/emailLists";
-$("#emailLists").attr("href", emailListURL);
-$("#emailListsChild").attr("href", emailListURL);
-
-var manageListsURL = "/emailMarketing/" + $("#domainNamePage").text() + "/manageLists";
-$("#manageLists").attr("href", manageListsURL);
-$("#manageListsChild").attr("href", manageListsURL);
-
-var sendEmailsURL = "/emailMarketing/sendEmails";
-$("#sendEmailsPage").attr("href", sendEmailsURL);
-$("#sendEmailsPageChild").attr("href", sendEmailsURL);
-
-var composeEmailURL = "/emailMarketing/composeEmailMessage";
-$("#composeEmails").attr("href", composeEmailURL);
-$("#composeEmailsChild").attr("href", composeEmailURL);
-
-var smtpHostsURL = "/emailMarketing/" + $("#domainNamePage").text() + "/manageSMTP";
-$("#manageSMTPHosts").attr("href", smtpHostsURL);
-$("#manageSMTPHostsChild").attr("href", smtpHostsURL);
-
-
-app.controller('emailMarketing', function ($scope, $http) {
-
- $scope.cyberPanelLoading = true;
- $scope.fetchUsers = function () {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/fetchUsers";
-
- var data = {};
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- $scope.users = JSON.parse(response.data.data);
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
- $scope.fetchUsers();
- $scope.enableDisableMarketing = function (status, userName) {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/enableDisableMarketing";
-
- var data = {userName: userName};
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- $scope.fetchUsers();
-
- if (response.data.status === 1) {
- new PNotify({
- title: 'Success!',
- text: 'Changes successfully saved.',
- type: 'success'
- });
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-});
-
-app.controller('createEmailList', function ($scope, $http, $timeout) {
-
- $scope.installationDetailsForm = false;
- $scope.installationProgress = true;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = true;
-
- var statusFile;
- var path;
-
-
- $scope.goBack = function () {
- $scope.installationDetailsForm = false;
- $scope.installationProgress = true;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = true;
- $("#installProgress").css("width", "0%");
- };
-
- $scope.createEmailList = function () {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = false;
- $scope.cyberPanelLoading = false;
- $scope.goBackDisable = true;
- $scope.currentStatus = "Starting to load email addresses..";
-
-
- url = "/emailMarketing/submitEmailList";
-
- var data = {
- domain: $("#domainNamePage").text(),
- path: $scope.path,
- listName: $scope.listName
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
- if (response.data.status === 1) {
- statusFile = response.data.tempStatusPath;
- getInstallStatus();
- } else {
-
- $scope.installationDetailsForm = true;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = false;
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
- function getInstallStatus() {
-
- url = "/websites/installWordpressStatus";
-
- var data = {
- statusFile: statusFile,
- domainName: $("#domainNamePage").text()
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
-
- if (response.data.abort === 1) {
-
- if (response.data.installStatus === 1) {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = false;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = false;
- $scope.currentStatus = 'Emails successfully loaded.';
- $timeout.cancel();
-
- } else {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = false;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = false;
- $scope.currentStatus = response.data.error_message;
-
-
- }
-
- } else {
- $scope.installPercentage = response.data.installationProgress;
- $scope.currentStatus = response.data.currentStatus;
-
- $timeout(getInstallStatus, 1000);
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
-
- }
-
-
- }
-
- $scope.fetchEmails = function () {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/fetchEmails";
-
- var data = {'listName': $scope.listName};
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- $scope.records = JSON.parse(response.data.data);
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
-
-});
-
-app.controller('manageEmailLists', function ($scope, $http, $timeout) {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = true;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = true;
- $scope.verificationStatus = true;
-
- var statusFile;
- var path;
-
-
- $scope.goBack = function () {
- $scope.installationDetailsForm = false;
- $scope.installationProgress = true;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = true;
- $("#installProgress").css("width", "0%");
- };
-
- $scope.createEmailList = function () {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = false;
- $scope.cyberPanelLoading = false;
- $scope.goBackDisable = true;
- $scope.currentStatus = "Starting to load email addresses..";
-
-
- url = "/emailMarketing/submitEmailList";
-
- var data = {
- domain: $("#domainNamePage").text(),
- path: $scope.path,
- listName: $scope.listName
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
- if (response.data.status === 1) {
- statusFile = response.data.tempStatusPath;
- getInstallStatus();
- } else {
-
- $scope.installationDetailsForm = true;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = false;
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
- function getInstallStatus() {
-
- url = "/websites/installWordpressStatus";
-
- var data = {
- statusFile: statusFile,
- domainName: $("#domainNamePage").text()
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
-
- if (response.data.abort === 1) {
-
- if (response.data.installStatus === 1) {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = false;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = false;
- $scope.currentStatus = 'Emails successfully loaded.';
- $timeout.cancel();
-
- } else {
-
- $scope.installationDetailsForm = true;
- $scope.installationProgress = false;
- $scope.cyberPanelLoading = true;
- $scope.goBackDisable = false;
- $scope.currentStatus = response.data.error_message;
-
-
- }
-
- } else {
- $scope.installPercentage = response.data.installationProgress;
- $scope.currentStatus = response.data.currentStatus;
-
- $timeout(getInstallStatus, 1000);
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
-
- }
-
-
- }
-
-
- ///
-
- $scope.currentRecords = true;
-
- $scope.recordstoShow = 50;
- var globalPage;
-
- $scope.fetchRecords = function () {
- $scope.fetchEmails(globalPage);
- };
-
- $scope.fetchEmails = function (page) {
- globalPage = page;
- listVerificationStatus();
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/fetchEmails";
-
- var data = {
- 'listName': $scope.listName,
- 'recordstoShow': $scope.recordstoShow,
- 'page': page
-
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- $scope.currentRecords = false;
- $scope.records = JSON.parse(response.data.data);
- $scope.pagination = response.data.pagination;
- $scope.verificationButton = false;
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
- $scope.deleteList = function () {
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/deleteList";
-
- var data = {
- listName: $scope.listName
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- if (response.data.status === 1) {
- new PNotify({
- title: 'Success!',
- text: 'Emails Successfully Deleted.',
- type: 'success'
- });
- } else {
-
- $scope.cyberPanelLoading = false;
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
- $scope.showAddEmails = function () {
- $scope.installationDetailsForm = false;
- $scope.verificationStatus = true;
- };
-
- // List Verification
-
- $scope.startVerification = function () {
-
- $scope.currentStatusVerification = 'Email verification job started..';
- $scope.installationDetailsForm = true;
- $scope.verificationStatus = false;
- $scope.verificationButton = true;
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/emailVerificationJob";
-
- var data = {
- listName: $scope.listName
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
- if (response.data.status === 1) {
- listVerificationStatus();
- $scope.verificationButton = true;
- } else {
-
- $scope.cyberPanelLoading = true;
- $scope.verificationButton = false;
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- $scope.verificationButton = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
-
- };
-
- var globalCounter = 0;
-
- function listVerificationStatus() {
-
- $scope.verificationButton = true;
- $scope.cyberPanelLoading = false;
-
- url = "/websites/installWordpressStatus";
-
- var data = {
- domain: $("#domainNamePage").text(),
- statusFile: "/home/cyberpanel/" + $("#domainNamePage").text() + "/" + $scope.listName
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
-
- if (response.data.abort === 1) {
-
- if (response.data.installStatus === 1) {
- $scope.cyberPanelLoading = true;
- $scope.verificationButton = false;
- $scope.currentStatusVerification = 'Emails successfully verified.';
- $timeout.cancel();
-
- } else {
-
- if (response.data.error_message.search('No such file') > -1) {
- $scope.verificationButton = false;
- return;
- }
- $scope.verificationButton = true;
- $scope.cyberPanelLoading = false;
- $scope.verificationStatus = false;
- $scope.currentStatusVerification = response.data.error_message;
-
- }
-
- } else {
-
- if (response.data.currentStatus.search('No such file') > -1) {
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = true;
- $scope.jobStatus = true;
- $scope.goBackDisable = false;
- $timeout.cancel();
- return;
- }
-
- $scope.currentStatusVerification = response.data.currentStatus;
- $timeout(listVerificationStatus, 1000);
- $scope.verificationStatus = false;
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
-
- }
-
-
- }
-
- // Delete Email from list
-
- $scope.deleteEmail = function (id) {
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/deleteEmail";
-
- var data = {
- id: id
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- $scope.fetchEmails(globalPage);
-
- if (response.data.status === 1) {
- $scope.fetchEmails(globalPage);
- new PNotify({
- title: 'Success.',
- text: 'Email Successfully deleted.',
- type: 'success'
- });
-
- } else {
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
-
- $scope.currentPageLogs = 1;
- $scope.recordsToShowLogs = 10;
-
- $scope.fetchLogs = function () {
-
- $scope.cyberPanelLoading = false;
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- var data = {
- listName: $scope.listName,
- page: $scope.currentPageLogs,
- recordsToShow: $scope.recordsToShowLogs
- };
-
- url = "/emailMarketing/fetchVerifyLogs";
-
- $http.post(url, data, config).then(ListInitialData, cantLoadInitialData);
-
- function ListInitialData(response) {
- $scope.cyberPanelLoading = true;
- if (response.data.status === 1) {
- $scope.recordsLogs = JSON.parse(response.data.logs);
- $scope.paginationLogs = response.data.pagination;
- $scope.totalEmails = response.data.totalEmails;
- $scope.verified = response.data.verified;
- $scope.notVerified = response.data.notVerified;
- } else {
- new PNotify({
- title: 'Error!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
- function cantLoadInitialData(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
- }
-
-
- };
-
-
-});
-
-app.controller('manageSMTPHostsCTRL', function ($scope, $http) {
-
- $scope.cyberPanelLoading = true;
- $scope.fetchSMTPHosts = function () {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/fetchSMTPHosts";
-
- var data = {};
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- $scope.records = JSON.parse(response.data.data);
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
- $scope.fetchSMTPHosts();
- $scope.saveSMTPHost = function (status, userName) {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/saveSMTPHost";
-
- var data = {
- smtpHost: $scope.smtpHost,
- smtpPort: $scope.smtpPort,
- smtpUserName: $scope.smtpUserName,
- smtpPassword: $scope.smtpPassword
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- $scope.fetchSMTPHosts();
- new PNotify({
- title: 'Success!',
- text: 'Successfully saved new SMTP host.',
- type: 'success'
- });
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
- $scope.smtpHostOperations = function (operation, id) {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/smtpHostOperations";
-
- var data = {
- id: id,
- operation: operation
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- $scope.fetchSMTPHosts();
-
- if (response.data.status === 1) {
- new PNotify({
- title: 'Success!',
- text: response.data.message,
- type: 'success'
- });
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-});
-
-app.controller('composeMessageCTRL', function ($scope, $http) {
-
- $scope.cyberPanelLoading = true;
- $scope.saveTemplate = function (status, userName) {
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/saveEmailTemplate";
-
- var data = {
- name: $scope.name,
- subject: $scope.subject,
- fromName: $scope.fromName,
- fromEmail: $scope.fromEmail,
- replyTo: $scope.replyTo,
- emailMessage: $scope.emailMessage
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- new PNotify({
- title: 'Success!',
- text: 'Template successfully saved.',
- type: 'success'
- });
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-});
-
-app.controller('sendEmailsCTRL', function ($scope, $http, $timeout) {
-
- $scope.cyberPanelLoading = true;
- $scope.availableFunctions = true;
- $scope.sendEmailsView = true;
- $scope.jobStatus = true;
-
- // Button
-
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
-
- $scope.templateSelected = function () {
- $scope.availableFunctions = false;
- $scope.sendEmailsView = true;
- $scope.previewLink = '/emailMarketing/preview/' + $scope.selectedTemplate;
- $scope.jobStatus = true;
- emailJobStatus();
-
- };
-
- $scope.sendEmails = function () {
- $scope.sendEmailsView = false;
- $scope.fetchJobs();
- };
-
- $scope.fetchJobs = function () {
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/fetchJobs";
-
- var data = {
- 'selectedTemplate': $scope.selectedTemplate
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- $scope.currentRecords = false;
- $scope.records = JSON.parse(response.data.data);
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-
- $scope.startEmailJob = function () {
- $scope.cyberPanelLoading = false;
- $scope.deleteTemplateBTN = true;
- $scope.sendEmailBTN = true;
- $scope.sendEmailsView = true;
- $scope.goBackDisable = true;
-
- url = "/emailMarketing/startEmailJob";
-
-
- var data = {
- 'selectedTemplate': $scope.selectedTemplate,
- 'listName': $scope.listName,
- 'host': $scope.host,
- 'verificationCheck': $scope.verificationCheck,
- 'unsubscribeCheck': $scope.unsubscribeCheck
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- emailJobStatus();
- } else {
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = false;
- $scope.jobStatus = true;
- $scope.goBackDisable = false;
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
-
- };
-
- function emailJobStatus() {
-
- $scope.cyberPanelLoading = false;
- $scope.deleteTemplateBTN = true;
- $scope.sendEmailBTN = true;
- $scope.sendEmailsView = true;
- $scope.jobStatus = false;
- $scope.goBackDisable = true;
-
- url = "/websites/installWordpressStatus";
-
- var data = {
- domain: 'example.com',
- statusFile: "/home/cyberpanel/" + $scope.selectedTemplate + "_pendingJob"
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
-
-
- if (response.data.abort === 1) {
-
- if (response.data.installStatus === 1) {
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = true;
- $scope.jobStatus = false;
- $scope.goBackDisable = false;
- $scope.currentStatus = 'Emails successfully sent.';
- $scope.fetchJobs();
- $timeout.cancel();
-
- } else {
-
- if (response.data.error_message.search('No such file') > -1) {
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = true;
- $scope.jobStatus = true;
- $scope.goBackDisable = false;
- return;
- }
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = true;
- $scope.jobStatus = false;
- $scope.goBackDisable = false;
- $scope.currentStatus = response.data.error_message;
-
- }
-
- } else {
-
- if (response.data.currentStatus.search('No such file') > -1) {
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = true;
- $scope.jobStatus = true;
- $scope.goBackDisable = false;
- $timeout.cancel();
- return;
- }
-
- $scope.currentStatus = response.data.currentStatus;
- $timeout(emailJobStatus, 1000);
- $scope.cyberPanelLoading = false;
- $scope.deleteTemplateBTN = true;
- $scope.sendEmailBTN = true;
- $scope.sendEmailsView = true;
- $scope.jobStatus = false;
- $scope.goBackDisable = true;
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page.',
- type: 'error'
- });
-
-
- }
-
-
- }
-
- $scope.goBack = function () {
- $scope.cyberPanelLoading = true;
- $scope.deleteTemplateBTN = false;
- $scope.sendEmailBTN = false;
- $scope.sendEmailsView = false;
- $scope.jobStatus = true;
-
- };
-
- $scope.deleteTemplate = function () {
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/deleteTemplate";
-
- var data = {
- selectedTemplate: $scope.selectedTemplate
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
- new PNotify({
- title: 'Success.',
- text: 'Template Successfully deleted.',
- type: 'success'
- });
-
- } else {
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
- $scope.deleteJob = function (id) {
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/deleteJob";
-
- var data = {
- id: id
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- $scope.fetchJobs();
-
- if (response.data.status === 1) {
- new PNotify({
- title: 'Success.',
- text: 'Template Successfully deleted.',
- type: 'success'
- });
-
- } else {
-
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
-
- }
-
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = true;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-});
-
-app.controller('configureVerify', function ($scope, $http) {
-
- $scope.cyberPanelLoading = true;
- $scope.ipv4Hidden = true;
- $scope.ipv6Hidden = true;
- $scope.delayHidden = true;
-
- $scope.delayInitial = function () {
- if ($scope.delay === 'Disable') {
- $scope.delayHidden = true;
- } else {
- $scope.delayHidden = false;
- }
- };
- $scope.rotateInitial = function () {
- if ($scope.rotation === 'Disable') {
- $scope.rotationHidden = true;
- } else if ($scope.rotation === 'IPv4') {
- $scope.ipv4Hidden = false;
- $scope.ipv6Hidden = true;
- } else {
- $scope.ipv4Hidden = true;
- $scope.ipv6Hidden = false;
- }
- };
-
- $scope.saveChanges = function () {
-
- $scope.cyberPanelLoading = false;
-
- url = "/emailMarketing/saveConfigureVerify";
-
- var data = {
- domain: $("#domainName").text(),
- rotation: $scope.rotation,
- delay: $scope.delay,
- delayAfter: $scope.delayAfter,
- delayTime: $scope.delayTime,
- ipv4: $scope.ipv4,
- ipv6: $scope.ipv6
- };
-
- var config = {
- headers: {
- 'X-CSRFToken': getCookie('csrftoken')
- }
- };
-
- $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
-
-
- function ListInitialDatas(response) {
- $scope.cyberPanelLoading = true;
-
- if (response.data.status === 1) {
-
- new PNotify({
- title: 'Success!',
- text: 'Successfully saved verification settings.',
- type: 'success'
- });
- } else {
- new PNotify({
- title: 'Operation Failed!',
- text: response.data.error_message,
- type: 'error'
- });
- }
- }
-
- function cantLoadInitialDatas(response) {
- $scope.cyberPanelLoading = false;
- new PNotify({
- title: 'Operation Failed!',
- text: 'Could not connect to server, please refresh this page',
- type: 'error'
- });
-
- }
-
- };
-});
-
-
diff --git a/emailMarketing/static/emailMarketing/mailing.png b/emailMarketing/static/emailMarketing/mailing.png
deleted file mode 100644
index da227aa32..000000000
Binary files a/emailMarketing/static/emailMarketing/mailing.png and /dev/null differ
diff --git a/emailMarketing/static/emailMarketing/paper-plane.png b/emailMarketing/static/emailMarketing/paper-plane.png
deleted file mode 100644
index 79998aa8d..000000000
Binary files a/emailMarketing/static/emailMarketing/paper-plane.png and /dev/null differ
diff --git a/emailMarketing/static/emailMarketing/post-office.png b/emailMarketing/static/emailMarketing/post-office.png
deleted file mode 100644
index 7419b2b29..000000000
Binary files a/emailMarketing/static/emailMarketing/post-office.png and /dev/null differ
diff --git a/emailMarketing/templates/emailMarketing/composeMessages.html b/emailMarketing/templates/emailMarketing/composeMessages.html
deleted file mode 100644
index 8c6fae014..000000000
--- a/emailMarketing/templates/emailMarketing/composeMessages.html
+++ /dev/null
@@ -1,90 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Compose Email Message - CyberPanel" %}{% endblock %}
-{% block content %}
-
-{% load static %}
-{% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
{% trans "Compose Email Message" %}
-
{% trans "On this page you can compose email message to be sent out later." %}
-
-
-
-
- {% trans "Compose Email Message" %}
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/emailMarketing/templates/emailMarketing/configureVerify.html b/emailMarketing/templates/emailMarketing/configureVerify.html
deleted file mode 100644
index 3c33bc0d3..000000000
--- a/emailMarketing/templates/emailMarketing/configureVerify.html
+++ /dev/null
@@ -1,99 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Configure Email Verification - CyberPanel" %}{% endblock %}
-{% block content %}
-
- {% load static %}
- {% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
{% trans "Configure Email Verification" %}
-
{% trans "On this page you can configure parameters regarding how email verification is performed for " %}{{ domain }}
-
-
-
-
- {% trans "Compose Email Message" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/emailMarketing/templates/emailMarketing/createEmailList.html b/emailMarketing/templates/emailMarketing/createEmailList.html
deleted file mode 100644
index 17e6f6d61..000000000
--- a/emailMarketing/templates/emailMarketing/createEmailList.html
+++ /dev/null
@@ -1,75 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Create Email List - CyberPanel" %}{% endblock %}
-{% block content %}
-
-{% load static %}
-{% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
{% trans "Create Email List" %} - {{ domain }}
-
{% trans "Create email list, to send out news letters and marketing emails." %}
-
-
-
-
- {% trans "Create Email List" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
-
diff --git a/emailMarketing/templates/emailMarketing/emailMarketing.html b/emailMarketing/templates/emailMarketing/emailMarketing.html
deleted file mode 100644
index e2ba1970b..000000000
--- a/emailMarketing/templates/emailMarketing/emailMarketing.html
+++ /dev/null
@@ -1,72 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Email Marketing - CyberPanel" %}{% endblock %}
-{% block content %}
-
-{% load static %}
-{% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
-
{% trans "Email Marketing" %}
-
{% trans "Select users to Enable/Disable Email Marketing feature!" %}
-
-
-
-
-
-
-
- {% if installCheck == 0 %}
-
-
- {% else %}
-
-
-
-
-
- {% trans 'ID' %}
- {% trans 'Username' %}
- {% trans 'Status' %}
-
-
-
-
-
-
-
-
-
- {% trans 'Disable' %}
-
- {% trans 'Enable' %}
-
-
-
-
-
-
-
-
- {% endif %}
-
-
-
-
-
-{% endblock %}
diff --git a/emailMarketing/templates/emailMarketing/manageLists.html b/emailMarketing/templates/emailMarketing/manageLists.html
deleted file mode 100644
index 541e0e301..000000000
--- a/emailMarketing/templates/emailMarketing/manageLists.html
+++ /dev/null
@@ -1,315 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Manage Email Lists - CyberPanel" %}{% endblock %}
-{% block content %}
-
- {% load static %}
- {% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
{% trans "Manage Email Lists" %} - {{ domain }}
-
{% trans "On this page you can manage your email lists (Delete, Verify, Add More Emails)." %}
-
-
-
-
- {% trans "Manage Email Lists" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/emailMarketing/templates/emailMarketing/manageSMTPHosts.html b/emailMarketing/templates/emailMarketing/manageSMTPHosts.html
deleted file mode 100644
index 2b94ddf05..000000000
--- a/emailMarketing/templates/emailMarketing/manageSMTPHosts.html
+++ /dev/null
@@ -1,126 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Manage SMTP Hosts - CyberPanel" %}{% endblock %}
-{% block content %}
-
-{% load static %}
-{% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
{% trans "Manage SMTP Hosts" %}
-
{% trans "On this page you can manage STMP Host. (SMTP hosts are used to send emails)" %}
-
-
-
-
- {% trans "Manage SMTP Hosts" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/emailMarketing/templates/emailMarketing/sendEmails.html b/emailMarketing/templates/emailMarketing/sendEmails.html
deleted file mode 100644
index dee7c06dc..000000000
--- a/emailMarketing/templates/emailMarketing/sendEmails.html
+++ /dev/null
@@ -1,204 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{% trans "Send Emails - CyberPanel" %}{% endblock %}
-{% block content %}
-
-{% load static %}
-{% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
{% trans "Send Emails" %}
-
{% trans "On this page you can send emails to the lists you created using SMTP Hosts." %}
-
-
-
-
- {% trans "Send Emails" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/emailMarketing/templates/emailMarketing/website.html b/emailMarketing/templates/emailMarketing/website.html
deleted file mode 100644
index 052fea0d3..000000000
--- a/emailMarketing/templates/emailMarketing/website.html
+++ /dev/null
@@ -1,1134 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block title %}{{ domain }} - CyberPanel{% endblock %}
-{% block content %}
-
- {% load static %}
- {% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
-
-
{% trans "All functions related to a particular site." %}
-
-
- {% if not error %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% trans "Resource" %}
- {% trans "Usage" %}
- {% trans "Allowed" %}
-
-
-
-
- {% trans "FTP" %}
- {{ ftpUsed }}
- {{ ftpTotal }}
-
-
- {% trans "Databases" %}
- {{ databasesUsed }}
- {{ databasesTotal }}
-
-
-
-
- {% trans "Disk Usage" %}
- {{ diskInMB }} (MB)
- {{ diskInMBTotal }} (MB)
-
-
- {% trans "Bandwidth Usage" %}
- {{ bwInMB }} (MB)
- {{ bwInMBTotal }} (MB)
-
-
-
-
-
-
-
-
-
-
-
-
- {% trans "Disk Usage" %}
-
-
-
-
-
- {% trans "Bandwidth Usage" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% trans "Logs Fetched" %}
-
-
-
-
-
{% trans "Could not fetch logs, see the logs file through command line. Error message:" %}
- {$ errorMessage $}
-
-
-
-
-
{% trans "Could not connect to server. Please refresh this page." %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% trans "PHP Version Changed to:" %} {$ changedPHPVersion $}
-
-
-
-
{% trans "Deleted:" %} {$ deletedDomain $}
-
-
-
-
{% trans "SSL Issued:" %} {$ sslDomainIssued $}
-
-
-
-
{% trans "Changes applied successfully." %}
-
-
-
-
-
-
-
-
{% trans "Could not connect to server. Please refresh this page." %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% trans "SSL Saved" %}
-
-
-
-
-
{% trans "Could not save SSL. Error message:" %} {$ errorMessage $}
-
-
-
-
-
{% trans "Could not connect to server. Please refresh this page." %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% trans "Current configuration in the file fetched." %}
-
-
-
-
-
{% trans "Could not fetch current configuration. Error message:" %} {$
- errorMessage $}
-
-
-
-
-
{% trans "Could not connect to server. Please refresh this page." %}
-
-
-
-
{% trans "Configurations saved." %}
-
-
-
-
{% trans "Could not fetch current configuration. Error message:" %} {$
- errorMessage $}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% trans "Current rewrite rules in the file fetched." %} Click
- to read more about whats changed in rewrite
- rules from v1.7 onwards.
-
-
-
-
-
{% trans "Could not fetch current rewrite rules. Error message:" %} {$
- errorMessage $}
-
-
-
-
-
{% trans "Could not connect to server. Please refresh this page." %}
-
-
-
-
{% trans "Configurations saved." %}
-
-
-
-
{% trans "Could not save rewrite rules. Error message:" %} {$ errorMessage
- $}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% if marketingStatus %}
-
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% else %}
-
-
-
-
- {% endif %}
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/emailMarketing/tests.py b/emailMarketing/tests.py
deleted file mode 100644
index f067dcaac..000000000
--- a/emailMarketing/tests.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from django.test import TestCase
-
-# Create your tests here.
diff --git a/emailMarketing/urls.py b/emailMarketing/urls.py
deleted file mode 100644
index fd54fe972..000000000
--- a/emailMarketing/urls.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from django.urls import path, re_path
-from . import views
-
-urlpatterns = [
- path('', views.emailMarketing, name='emailMarketing'),
- path('fetchUsers', views.fetchUsers, name='fetchUsers'),
- path('enableDisableMarketing', views.enableDisableMarketing, name='enableDisableMarketing'),
- path('saveConfigureVerify', views.saveConfigureVerify, name='saveConfigureVerify'),
- path('fetchVerifyLogs', views.fetchVerifyLogs, name='fetchVerifyLogs'),
- re_path(r'^(?P
.+)/emailLists$', views.createEmailList, name='createEmailList'),
- path('submitEmailList', views.submitEmailList, name='submitEmailList'),
- re_path(r'^(?P.+)/manageLists$', views.manageLists, name='manageLists'),
- re_path(r'^(?P.+)/manageSMTP$', views.manageSMTP, name='manageSMTP'),
- re_path(r'^(?P.+)/configureVerify$', views.configureVerify, name='configureVerify'),
- path('fetchEmails', views.fetchEmails, name='fetchEmails'),
- path('deleteList', views.deleteList, name='deleteList'),
- path('emailVerificationJob', views.emailVerificationJob, name='emailVerificationJob'),
- path('deleteEmail', views.deleteEmail, name='deleteEmail'),
- path('saveSMTPHost', views.saveSMTPHost, name='saveSMTPHost'),
- path('fetchSMTPHosts', views.fetchSMTPHosts, name='fetchSMTPHosts'),
- path('smtpHostOperations', views.smtpHostOperations, name='smtpHostOperations'),
- path('composeEmailMessage', views.composeEmailMessage, name='composeEmailMessage'),
- path('saveEmailTemplate', views.saveEmailTemplate, name='saveEmailTemplate'),
- path('sendEmails', views.sendEmails, name='sendEmails'),
- re_path(r'^preview/(?P[-\w]+)/$', views.templatePreview, name='templatePreview'),
- path('fetchJobs', views.fetchJobs, name='fetchJobs'),
- path('startEmailJob', views.startEmailJob, name='startEmailJob'),
- path('deleteTemplate', views.deleteTemplate, name='deleteTemplate'),
- path('deleteJob', views.deleteJob, name='deleteJob'),
- re_path(r'^remove/(?P[-\w]+)/(?P\w+@.+)$', views.remove, name='remove'),
-]
diff --git a/emailMarketing/views.py b/emailMarketing/views.py
deleted file mode 100644
index 9b1e6b0ee..000000000
--- a/emailMarketing/views.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from django.shortcuts import redirect
-from loginSystem.views import loadLoginPage
-from .emailMarketingManager import EmailMarketingManager
-# Create your views here.
-
-
-def emailMarketing(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.emailMarketing()
- except KeyError:
- return redirect(loadLoginPage)
-
-def fetchUsers(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.fetchUsers()
- except KeyError:
- return redirect(loadLoginPage)
-
-def enableDisableMarketing(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.enableDisableMarketing()
- except KeyError:
- return redirect(loadLoginPage)
-
-def createEmailList(request, domain):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request, domain)
- return emm.createEmailList()
- except KeyError:
- return redirect(loadLoginPage)
-
-def submitEmailList(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.submitEmailList()
- except KeyError:
- return redirect(loadLoginPage)
-
-def manageLists(request, domain):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request, domain)
- return emm.manageLists()
- except KeyError:
- return redirect(loadLoginPage)
-
-def configureVerify(request, domain):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request, domain)
- return emm.configureVerify()
- except KeyError:
- return redirect(loadLoginPage)
-
-def saveConfigureVerify(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.saveConfigureVerify()
- except KeyError:
- return redirect(loadLoginPage)
-
-def fetchVerifyLogs(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.fetchVerifyLogs()
- except KeyError:
- return redirect(loadLoginPage)
-
-def fetchEmails(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.fetchEmails()
- except KeyError:
- return redirect(loadLoginPage)
-
-def deleteList(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.deleteList()
- except KeyError:
- return redirect(loadLoginPage)
-
-def emailVerificationJob(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.emailVerificationJob()
- except KeyError:
- return redirect(loadLoginPage)
-
-def deleteEmail(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.deleteEmail()
- except KeyError:
- return redirect(loadLoginPage)
-
-def manageSMTP(request, domain):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request, domain)
- return emm.manageSMTP()
- except KeyError:
- return redirect(loadLoginPage)
-
-def saveSMTPHost(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.saveSMTPHost()
- except KeyError:
- return redirect(loadLoginPage)
-
-def fetchSMTPHosts(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.fetchSMTPHosts()
- except KeyError:
- return redirect(loadLoginPage)
-
-def smtpHostOperations(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.smtpHostOperations()
- except KeyError:
- return redirect(loadLoginPage)
-
-def composeEmailMessage(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.composeEmailMessage()
- except KeyError:
- return redirect(loadLoginPage)
-
-def saveEmailTemplate(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.saveEmailTemplate()
- except KeyError:
- return redirect(loadLoginPage)
-
-def sendEmails(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.sendEmails()
- except KeyError:
- return redirect(loadLoginPage)
-
-def templatePreview(request, templateName):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request, templateName)
- return emm.templatePreview()
- except KeyError:
- return redirect(loadLoginPage)
-
-def fetchJobs(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.fetchJobs()
- except KeyError:
- return redirect(loadLoginPage)
-
-def startEmailJob(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.startEmailJob()
- except KeyError:
- return redirect(loadLoginPage)
-
-def deleteTemplate(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.deleteTemplate()
- except KeyError:
- return redirect(loadLoginPage)
-
-def deleteJob(request):
- try:
- userID = request.session['userID']
- emm = EmailMarketingManager(request)
- return emm.deleteJob()
- except KeyError:
- return redirect(loadLoginPage)
-
-
-def remove(request, listName, emailAddress):
- try:
- emm = EmailMarketingManager(request)
- return emm.remove(listName, emailAddress)
- except KeyError:
- return redirect(loadLoginPage)
\ No newline at end of file
diff --git a/examplePlugin/__init__.py b/examplePlugin/__init__.py
deleted file mode 100644
index b3f015833..000000000
--- a/examplePlugin/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-default_app_config = 'examplePlugin.apps.ExamplepluginConfig'
diff --git a/examplePlugin/admin.py b/examplePlugin/admin.py
deleted file mode 100644
index 8c38f3f3d..000000000
--- a/examplePlugin/admin.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.
diff --git a/examplePlugin/apps.py b/examplePlugin/apps.py
deleted file mode 100644
index 6f64e3571..000000000
--- a/examplePlugin/apps.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from django.apps import AppConfig
-
-
-class ExamplepluginConfig(AppConfig):
- name = 'examplePlugin'
-
- def ready(self):
- from . import signals
diff --git a/examplePlugin/enable_migrations b/examplePlugin/enable_migrations
deleted file mode 100644
index e69de29bb..000000000
diff --git a/examplePlugin/meta.xml b/examplePlugin/meta.xml
deleted file mode 100644
index 9e7e58b4d..000000000
--- a/examplePlugin/meta.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- examplePlugin
- Utility
- This is an example plugin
- 1.0.1
- usmannasir
-
\ No newline at end of file
diff --git a/examplePlugin/migrations/__init__.py b/examplePlugin/migrations/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/examplePlugin/models.py b/examplePlugin/models.py
deleted file mode 100644
index c2f360a3c..000000000
--- a/examplePlugin/models.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from django.db import models
-
-
-class ExamplePlugin(models.Model):
- name = models.CharField(unique=True, max_length=255)
-
- class Meta:
- # db_table = "ExamplePlugin"
- pass
diff --git a/examplePlugin/post_install b/examplePlugin/post_install
deleted file mode 100644
index 01ec2cce3..000000000
--- a/examplePlugin/post_install
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/local/CyberCP/bin/python
-RESET = '\033[0;0m'
-BLUE = "\033[0;34m"
-print(BLUE + "Running Post-Install Script..." + RESET)
diff --git a/examplePlugin/pre_install b/examplePlugin/pre_install
deleted file mode 100644
index c14bef694..000000000
--- a/examplePlugin/pre_install
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/local/CyberCP/bin/python
-RESET = '\033[0;0m'
-GREEN = '\033[0;32m'
-print(GREEN + "Running Pre-Install Script..." + RESET)
diff --git a/examplePlugin/pre_remove b/examplePlugin/pre_remove
deleted file mode 100644
index eb54102ec..000000000
--- a/examplePlugin/pre_remove
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/local/CyberCP/bin/python
-RESET = '\033[0;0m'
-GREEN = '\033[0;32m'
-print(GREEN + "Running Pre-Remove Script..." + RESET)
diff --git a/examplePlugin/signals.py b/examplePlugin/signals.py
deleted file mode 100644
index 0c4d14f7c..000000000
--- a/examplePlugin/signals.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from django.dispatch import receiver
-from django.http import HttpResponse
-from websiteFunctions.signals import postWebsiteDeletion
-from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
-
-
-# This plugin respond to an event after CyberPanel core finished deleting a website.
-# Original request object is passed, body can be accessed with request.body.
-
-# If any Event handler returns a response object, CyberPanel will stop further processing and returns your response to browser.
-# To continue processing just return 200 from your events handlers.
-
-@receiver(postWebsiteDeletion)
-def rcvr(sender, **kwargs):
- request = kwargs['request']
- logging.writeToFile('Hello World from Example Plugin.')
- return HttpResponse('Hello World from Example Plugin.')
diff --git a/examplePlugin/static/examplePlugin/examplePlugin.js b/examplePlugin/static/examplePlugin/examplePlugin.js
deleted file mode 100644
index c10ce8398..000000000
--- a/examplePlugin/static/examplePlugin/examplePlugin.js
+++ /dev/null
@@ -1,3 +0,0 @@
-$(document).ready(function () {
- console.log("using JS in static file...!");
-});
\ No newline at end of file
diff --git a/examplePlugin/templates/examplePlugin/examplePlugin.html b/examplePlugin/templates/examplePlugin/examplePlugin.html
deleted file mode 100644
index 428ac6c05..000000000
--- a/examplePlugin/templates/examplePlugin/examplePlugin.html
+++ /dev/null
@@ -1,52 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% block styles %}
-
-{% endblock %}
-{% block title %}Example plugin - CyberPanel{% endblock %}
-{% block content %}
- {% load static %}
- {% get_current_language as LANGUAGE_CODE %}
-
-
-
-
-
{% trans "Example Plugin Page" %}
-
{% trans "Example Plugin Info" %}
-
-
-
-
-
{% trans "examplePlugin" %}
-
-
-
-
-
-{% endblock %}
-
-{% block footer_scripts %}
-
- {# #}
-
-
-{% endblock %}
diff --git a/examplePlugin/tests.py b/examplePlugin/tests.py
deleted file mode 100644
index 7ce503c2d..000000000
--- a/examplePlugin/tests.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.
diff --git a/examplePlugin/urls.py b/examplePlugin/urls.py
deleted file mode 100644
index 421972e1a..000000000
--- a/examplePlugin/urls.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.urls import path
-from . import views
-
-urlpatterns = [
- path('', views.examplePlugin, name='examplePlugin'),
-]
-
diff --git a/examplePlugin/views.py b/examplePlugin/views.py
deleted file mode 100644
index 2845a8f61..000000000
--- a/examplePlugin/views.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.shortcuts import render, HttpResponse
-
-
-# Create your views here.
-
-def examplePlugin(request):
- return render(request, 'examplePlugin/examplePlugin.html')
diff --git a/install/install.py b/install/install.py
index 51d98ef71..53c5ab69e 100644
--- a/install/install.py
+++ b/install/install.py
@@ -3235,7 +3235,7 @@ password="%s"
apps_with_migrations = [
'loginSystem', 'packages', 'websiteFunctions', 'baseTemplate', 'userManagment',
'dns', 'databases', 'ftp', 'filemanager', 'mailServer', 'emailPremium',
- 'emailMarketing', 'cloudAPI', 'containerization', 'IncBackups', 'CLManager',
+ 'cloudAPI', 'containerization', 'IncBackups', 'CLManager',
's3Backups', 'dockerManager', 'aiScanner', 'firewall', 'tuning', 'serverStatus',
'serverLogs', 'backup', 'managePHP', 'manageSSL', 'api', 'manageServices',
'pluginHolder', 'highAvailability', 'WebTerminal'
diff --git a/paypalPremiumPlugin/README.md b/paypalPremiumPlugin/README.md
deleted file mode 100644
index 922bffe2e..000000000
--- a/paypalPremiumPlugin/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Premium Plugin Example
-
-An example paid plugin for CyberPanel that demonstrates how to implement Patreon subscription-based plugin access.
-
-## Features
-
-- Requires Patreon subscription to "CyberPanel Paid Plugin" tier
-- Users can install the plugin without subscription
-- Plugin functionality is locked until subscription is verified
-- Shows subscription required page when accessed without subscription
-
-## Installation
-
-1. Upload the plugin ZIP file to CyberPanel
-2. Install the plugin from the plugin manager
-3. The plugin will appear in the installed plugins list
-
-## Usage
-
-### For Users Without Subscription
-
-- Plugin can be installed
-- When accessing the plugin, a subscription required page is shown
-- Link to Patreon subscription page is provided
-
-### For Users With Subscription
-
-- Plugin works normally
-- All features are accessible
-- Settings page is available
-
-## Configuration
-
-The plugin checks for Patreon membership via the Patreon API. Make sure to configure:
-
-1. Patreon Client ID
-2. Patreon Client Secret
-3. Patreon Creator ID
-
-These should be set in CyberPanel environment variables or settings.
-
-## Meta.xml Structure
-
-The plugin uses the following meta.xml structure for paid plugins:
-
-```xml
-true
-CyberPanel Paid Plugin
-https://www.patreon.com/c/newstargeted/membership
-```
-
-## Author
-
-master3395
-
-## License
-
-MIT
diff --git a/paypalPremiumPlugin/__init__.py b/paypalPremiumPlugin/__init__.py
deleted file mode 100644
index f80c90067..000000000
--- a/paypalPremiumPlugin/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# PayPal Premium Plugin Example
-# This is a paid plugin that requires PayPal payment
-
-default_app_config = 'paypalPremiumPlugin.apps.PaypalpremiumpluginConfig'
diff --git a/paypalPremiumPlugin/api_encryption.py b/paypalPremiumPlugin/api_encryption.py
deleted file mode 100644
index 8f2820ab2..000000000
--- a/paypalPremiumPlugin/api_encryption.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-AES-256-CBC encryption for plugin <-> api.newstargeted.com communication.
-Key must match PLUGIN_VERIFICATION_CIPHER_KEY in config.php on the API server.
-"""
-import json
-import base64
-import os
-
-CIPHER_KEY_B64 = '1VLPEKTmLGUbIxHUFEtsuVM2MPN1tl8HPFtyJc4dr58='
-ENCRYPTION_ENABLED = True
-
-_ENCRYPTION_CIPHER_KEY = None
-
-
-def _get_key():
- global _ENCRYPTION_CIPHER_KEY
- if _ENCRYPTION_CIPHER_KEY is not None:
- return _ENCRYPTION_CIPHER_KEY
- try:
- key = base64.b64decode(CIPHER_KEY_B64)
- if len(key) == 32:
- _ENCRYPTION_CIPHER_KEY = key
- return key
- except Exception:
- pass
- return None
-
-
-def encrypt_payload(data):
- if not ENCRYPTION_ENABLED or not _get_key():
- body = json.dumps(data, separators=(',', ':')).encode('utf-8')
- return body, {'Content-Type': 'application/json'}
- try:
- from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
- from cryptography.hazmat.primitives import padding
- from cryptography.hazmat.backends import default_backend
- key = _get_key()
- plain = json.dumps(data, separators=(',', ':')).encode('utf-8')
- padder = padding.PKCS7(128).padder()
- padded = padder.update(plain) + padder.finalize()
- iv = os.urandom(16)
- cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
- encryptor = cipher.encryptor()
- ciphertext = encryptor.update(padded) + encryptor.finalize()
- payload = base64.b64encode(iv).decode('ascii') + '.' + base64.b64encode(ciphertext).decode('ascii')
- return payload.encode('utf-8'), {'Content-Type': 'text/plain', 'X-Encrypted': '1'}
- except Exception:
- body = json.dumps(data, separators=(',', ':')).encode('utf-8')
- return body, {'Content-Type': 'application/json'}
-
-
-def decrypt_response(body_bytes, content_type='', expect_encrypted=False):
- try:
- body_str = body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else str(body_bytes)
- is_encrypted = (
- expect_encrypted or
- ('text/plain' in content_type and '.' in body_str) or
- ('.' in body_str and body_str.strip() and body_str.strip()[0] not in '{[')
- )
- parts = body_str.strip().split('.', 1)
- if is_encrypted and len(parts) == 2 and ENCRYPTION_ENABLED and _get_key():
- from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
- from cryptography.hazmat.primitives import padding
- from cryptography.hazmat.backends import default_backend
- iv = base64.b64decode(parts[0])
- ciphertext = base64.b64decode(parts[1])
- key = _get_key()
- cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
- decryptor = cipher.decryptor()
- padded = decryptor.update(ciphertext) + decryptor.finalize()
- unpadder = padding.PKCS7(128).unpadder()
- plain = unpadder.update(padded) + unpadder.finalize()
- return json.loads(plain.decode('utf-8'))
- return json.loads(body_str)
- except Exception:
- try:
- return json.loads(body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else body_bytes)
- except Exception:
- return {}
diff --git a/paypalPremiumPlugin/apps.py b/paypalPremiumPlugin/apps.py
deleted file mode 100644
index 0f2389e23..000000000
--- a/paypalPremiumPlugin/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-class PaypalpremiumpluginConfig(AppConfig):
- name = 'paypalPremiumPlugin'
- verbose_name = 'PayPal Premium Plugin Example'
diff --git a/paypalPremiumPlugin/meta.xml b/paypalPremiumPlugin/meta.xml
deleted file mode 100644
index 6535e1409..000000000
--- a/paypalPremiumPlugin/meta.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
- PayPal Premium Plugin Example
- Utility
- 1.0.2
- An example paid plugin that requires PayPal payment. Users can install it but cannot run it without payment. Supports PayPal.me links and PayPal Payment Links/Buttons.
- master3395
- https://github.com/master3395/cyberpanel-plugins
- MIT
-
- 3.6+
- 2.2+
- 2.5.5+
-
-
- 2.5.5
- 3.0.0
-
-
- true
- false
-
- true
- CyberPanel Paid Plugin
- https://www.patreon.com/membership/27789984
- https://paypal.me/KimBS?locale.x=en_US&country.x=NO
-
- /plugins/paypalPremiumPlugin/
- /plugins/paypalPremiumPlugin/settings/
-
diff --git a/paypalPremiumPlugin/migrations/0001_initial.py b/paypalPremiumPlugin/migrations/0001_initial.py
deleted file mode 100644
index 97b0f3fa8..000000000
--- a/paypalPremiumPlugin/migrations/0001_initial.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated migration for PaypalPremiumPluginConfig
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = []
-
- operations = [
- migrations.CreateModel(
- name='PaypalPremiumPluginConfig',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('payment_method', models.CharField(choices=[('patreon', 'Patreon Subscription'), ('paypal', 'PayPal Payment'), ('both', 'Check Both (Patreon or PayPal)')], default='both', help_text='Choose which payment method to use for verification.', max_length=10)),
- ('activation_key', models.CharField(blank=True, default='', help_text='Validated activation key - grants access without re-entering.', max_length=64)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('updated_at', models.DateTimeField(auto_now=True)),
- ],
- options={
- 'verbose_name': 'PayPal Premium Plugin Configuration',
- 'verbose_name_plural': 'PayPal Premium Plugin Configurations',
- },
- ),
- ]
diff --git a/paypalPremiumPlugin/migrations/__init__.py b/paypalPremiumPlugin/migrations/__init__.py
deleted file mode 100644
index 2a0ee1c3e..000000000
--- a/paypalPremiumPlugin/migrations/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# PayPal Premium Plugin migrations
diff --git a/paypalPremiumPlugin/models.py b/paypalPremiumPlugin/models.py
deleted file mode 100644
index b56e0c6e4..000000000
--- a/paypalPremiumPlugin/models.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- coding: utf-8 -*-
-from django.db import models
-
-
-class PaypalPremiumPluginConfig(models.Model):
- PAYMENT_METHOD_CHOICES = [
- ('patreon', 'Patreon Subscription'),
- ('paypal', 'PayPal Payment'),
- ('both', 'Check Both (Patreon or PayPal)'),
- ]
- payment_method = models.CharField(
- max_length=10,
- choices=PAYMENT_METHOD_CHOICES,
- default='both',
- help_text="Choose which payment method to use for verification."
- )
- activation_key = models.CharField(
- max_length=64,
- blank=True,
- default='',
- help_text="Validated activation key - grants access without re-entering."
- )
- created_at = models.DateTimeField(auto_now_add=True)
- updated_at = models.DateTimeField(auto_now=True)
-
- class Meta:
- verbose_name = "PayPal Premium Plugin Configuration"
- verbose_name_plural = "PayPal Premium Plugin Configurations"
-
- def __str__(self):
- return "PayPal Premium Plugin Configuration"
-
- @classmethod
- def get_config(cls):
- config, _ = cls.objects.get_or_create(pk=1)
- return config
-
- def save(self, *args, **kwargs):
- self.pk = 1
- super().save(*args, **kwargs)
diff --git a/paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html b/paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html
deleted file mode 100644
index ac5f39dbc..000000000
--- a/paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html
+++ /dev/null
@@ -1,96 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "PayPal Premium Plugin Example - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
{% trans "Premium Features" %}
-
- {% for feature in features %}
- {{ feature }}
- {% endfor %}
-
-
-
-{% endblock %}
diff --git a/paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html b/paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html
deleted file mode 100644
index f7c9c39c6..000000000
--- a/paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html
+++ /dev/null
@@ -1,331 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "PayPal Premium Plugin Settings - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-{% endblock %}
diff --git a/paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html b/paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html
deleted file mode 100644
index cf67af087..000000000
--- a/paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html
+++ /dev/null
@@ -1,139 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "Payment Required - PayPal Premium Plugin" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
{% trans "Premium Plugin Access Required" %}
-
{% trans "This plugin requires payment or subscription to access premium features." %}
-
-
-
-
{% trans "Activate Premium Access" %}
-
{% trans "If you received an activation key, enter it below." %}
-
-
- {% csrf_token %}
-
- {% trans "Activation Key" %}
-
-
-
- {% trans "Activate" %}
-
-
-
-
- {% if payment_method == 'both' %}
-
- {% trans "Current Payment Method:" %} {% trans "Check Both (Patreon or PayPal)" %}
-
- {% elif payment_method == 'patreon' %}
-
- {% trans "Current Payment Method:" %} {% trans "Patreon Subscription Only" %}
-
- {% elif payment_method == 'paypal' %}
-
- {% trans "Current Payment Method:" %} {% trans "PayPal Payment Only" %}
-
- {% endif %}
-
-
-
-
-
{% trans "How it works:" %}
-
- {% trans "Install the plugin (already done)" %}
- {% trans "Enter activation key, subscribe on Patreon, or pay via PayPal" %}
- {% trans "The plugin will automatically unlock" %}
-
-
-
- {% if error %}
-
- {% trans "Error:" %} {{ error }}
-
- {% endif %}
-
-
-
-
-{% endblock %}
diff --git a/paypalPremiumPlugin/urls.py b/paypalPremiumPlugin/urls.py
deleted file mode 100644
index 997fe20f5..000000000
--- a/paypalPremiumPlugin/urls.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from django.urls import path, re_path
-from . import views
-
-app_name = 'paypalPremiumPlugin'
-
-urlpatterns = [
- path('', views.main_view, name='main'),
- path('settings/', views.settings_view, name='settings'),
- re_path(r'^activate-key/$', views.activate_key, name='activate_key'),
- path('save-payment-method/', views.save_payment_method, name='save_payment_method'),
- path('api/status/', views.api_status_view, name='api_status'),
-]
diff --git a/paypalPremiumPlugin/views.py b/paypalPremiumPlugin/views.py
deleted file mode 100644
index c1f96f129..000000000
--- a/paypalPremiumPlugin/views.py
+++ /dev/null
@@ -1,387 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-PayPal Premium Plugin Views - Unified Verification (same as contaboAutoSnapshot)
-Supports: Plugin Grants, Activation Key, Patreon, PayPal, AES encryption
-"""
-
-from django.shortcuts import render, redirect
-from django.http import JsonResponse, HttpResponse
-from django.views.decorators.http import require_http_methods
-from plogical.mailUtilities import mailUtilities
-from plogical.httpProc import httpProc
-from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
-from functools import wraps
-import urllib.request
-import urllib.error
-import json
-import time
-
-from .models import PaypalPremiumPluginConfig
-from . import api_encryption
-
-PLUGIN_NAME = 'paypalPremiumPlugin'
-PLUGIN_VERSION = '1.0.2'
-
-REMOTE_VERIFICATION_PATREON_URL = 'https://api.newstargeted.com/api/verify-patreon-membership.php'
-REMOTE_VERIFICATION_PAYPAL_URL = 'https://api.newstargeted.com/api/verify-paypal-payment.php'
-REMOTE_VERIFICATION_PLUGIN_GRANT_URL = 'https://api.newstargeted.com/api/verify-plugin-grant.php'
-REMOTE_ACTIVATION_KEY_URL = 'https://api.newstargeted.com/api/activate-plugin-key.php'
-
-PATREON_TIER = 'CyberPanel Paid Plugin'
-PATREON_URL = 'https://www.patreon.com/membership/27789984'
-PAYPAL_ME_URL = 'https://paypal.me/KimBS?locale.x=en_US&country.x=NO'
-PAYPAL_PAYMENT_LINK = ''
-
-
-def cyberpanel_login_required(view_func):
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- try:
- if not request.session.get('userID'):
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
- return view_func(request, *args, **kwargs)
- except KeyError:
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
- return _wrapped_view
-
-
-def _api_request(url, data, timeout=10):
- try:
- body, extra_headers = api_encryption.encrypt_payload(data)
- headers = {
- 'User-Agent': f'CyberPanel-Plugin/{PLUGIN_VERSION}',
- 'X-Plugin-Name': PLUGIN_NAME
- }
- headers.update(extra_headers)
- req = urllib.request.Request(url, data=body, headers=headers)
- with urllib.request.urlopen(req, timeout=timeout) as response:
- raw = response.read()
- ct = response.headers.get('Content-Type', '')
- expect_enc = extra_headers.get('X-Encrypted') == '1'
- return api_encryption.decrypt_response(raw, ct, expect_encrypted=expect_enc)
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: API request error to {url}: {str(e)}")
- return {}
-
-
-def check_plugin_grant(user_email, user_ip='', domain=''):
- try:
- request_data = {
- 'user_email': user_email or '',
- 'plugin_name': PLUGIN_NAME,
- 'user_ip': user_ip,
- 'domain': domain,
- }
- data = _api_request(REMOTE_VERIFICATION_PLUGIN_GRANT_URL, request_data)
- if data.get('success') and data.get('has_access'):
- return {'has_access': True, 'message': data.get('message', 'Access granted via Plugin Grants')}
- return {'has_access': False, 'message': data.get('message', '')}
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Plugin grant check error: {str(e)}")
- return {'has_access': False, 'message': ''}
-
-
-def check_patreon_membership(user_email, user_ip='', domain=''):
- try:
- request_data = {
- 'user_email': user_email,
- 'plugin_name': PLUGIN_NAME,
- 'plugin_version': PLUGIN_VERSION,
- 'user_ip': user_ip,
- 'domain': domain,
- 'tier_id': '27789984'
- }
- response_data = _api_request(REMOTE_VERIFICATION_PATREON_URL, request_data)
- if response_data.get('success', False):
- return {
- 'has_access': response_data.get('has_access', False),
- 'patreon_tier': response_data.get('patreon_tier', PATREON_TIER),
- 'patreon_url': response_data.get('patreon_url', PATREON_URL),
- 'message': response_data.get('message', 'Access granted'),
- 'error': None
- }
- return {
- 'has_access': False,
- 'patreon_tier': PATREON_TIER,
- 'patreon_url': PATREON_URL,
- 'message': response_data.get('message', 'Patreon subscription required'),
- 'error': response_data.get('error')
- }
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Patreon check error: {str(e)}")
- return {'has_access': False, 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL, 'message': 'Unable to verify Patreon.', 'error': str(e)}
-
-
-def check_paypal_payment(user_email, user_ip='', domain=''):
- try:
- request_data = {
- 'user_email': user_email,
- 'plugin_name': PLUGIN_NAME,
- 'plugin_version': PLUGIN_VERSION,
- 'user_ip': user_ip,
- 'domain': domain,
- 'timestamp': int(time.time()),
- }
- response_data = _api_request(REMOTE_VERIFICATION_PAYPAL_URL, request_data)
- if response_data.get('success', False):
- return {
- 'has_access': response_data.get('has_access', False),
- 'paypal_me_url': response_data.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': response_data.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': response_data.get('message', 'Access granted'),
- 'error': None
- }
- return {
- 'has_access': False,
- 'paypal_me_url': PAYPAL_ME_URL,
- 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': response_data.get('message', 'PayPal payment required'),
- 'error': response_data.get('error')
- }
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: PayPal check error: {str(e)}")
- return {'has_access': False, 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK, 'message': 'Unable to verify PayPal.', 'error': str(e)}
-
-
-def unified_verification_required(view_func):
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- try:
- if not request.session.get('userID'):
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
-
- user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '') or getattr(request.user, 'username', '')
-
- try:
- config = PaypalPremiumPluginConfig.get_config()
- payment_method = config.payment_method
- except Exception:
- payment_method = 'both'
-
- has_access = False
- verification_result = {}
-
- activation_key = request.GET.get('activation_key') or request.POST.get('activation_key')
- if not activation_key:
- try:
- config = PaypalPremiumPluginConfig.get_config()
- activation_key = getattr(config, 'activation_key', '') or ''
- except Exception:
- activation_key = ''
-
- if activation_key:
- try:
- request_data = {'activation_key': activation_key.strip(), 'plugin_name': PLUGIN_NAME, 'user_email': user_email}
- response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data)
- if response_data.get('success', False) and response_data.get('has_access', False):
- has_access = True
- verification_result = {'method': 'activation_key', 'has_access': True, 'message': response_data.get('message', 'Access activated via key')}
- try:
- config = PaypalPremiumPluginConfig.get_config()
- config.activation_key = activation_key.strip()
- config.save(update_fields=['activation_key', 'updated_at'])
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Could not persist activation key: {str(e)}")
- elif not response_data.get('success') and activation_key:
- try:
- config = PaypalPremiumPluginConfig.get_config()
- if getattr(config, 'activation_key', '') == activation_key.strip():
- config.activation_key = ''
- config.save(update_fields=['activation_key', 'updated_at'])
- except Exception:
- pass
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Activation key check error: {str(e)}")
-
- if not has_access:
- grant_result = check_plugin_grant(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- if grant_result.get('has_access'):
- has_access = True
- verification_result = {'method': 'plugin_grant', 'has_access': True, 'message': grant_result.get('message', 'Access granted via Plugin Grants')}
-
- if not has_access:
- try:
- if payment_method == 'patreon':
- result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- has_access = result.get('has_access', False)
- verification_result = {
- 'method': 'patreon', 'has_access': has_access,
- 'patreon_tier': result.get('patreon_tier', PATREON_TIER),
- 'patreon_url': result.get('patreon_url', PATREON_URL),
- 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': result.get('message', 'Patreon subscription required'),
- 'error': result.get('error')
- }
- elif payment_method == 'paypal':
- result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- has_access = result.get('has_access', False)
- verification_result = {
- 'method': 'paypal', 'has_access': has_access,
- 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL,
- 'paypal_me_url': result.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': result.get('message', 'PayPal payment required'),
- 'error': result.get('error')
- }
- else:
- patreon_result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- paypal_result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- has_access = patreon_result.get('has_access', False) or paypal_result.get('has_access', False)
- verification_result = {
- 'method': 'both', 'has_access': has_access,
- 'patreon_tier': patreon_result.get('patreon_tier', PATREON_TIER),
- 'patreon_url': patreon_result.get('patreon_url', PATREON_URL),
- 'paypal_me_url': paypal_result.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': paypal_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': 'Payment or subscription required' if not has_access else 'Access granted'
- }
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Verification error: {str(e)}")
- has_access = False
- verification_result = {
- 'method': payment_method, 'has_access': False,
- 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL,
- 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': 'Unable to verify access.', 'error': str(e)
- }
-
- if not has_access:
- context = {
- 'plugin_name': 'PayPal Premium Plugin Example',
- 'is_paid': True,
- 'payment_method': payment_method,
- 'verification_result': verification_result,
- 'patreon_tier': verification_result.get('patreon_tier', PATREON_TIER),
- 'patreon_url': verification_result.get('patreon_url', PATREON_URL),
- 'paypal_me_url': verification_result.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': verification_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': verification_result.get('message', 'Payment or subscription required'),
- 'error': verification_result.get('error')
- }
- proc = httpProc(request, 'paypalPremiumPlugin/subscription_required.html', context, 'admin')
- return proc.render()
-
- if has_access and verification_result:
- request.session['paypal_premium_access_via'] = verification_result.get('method', '')
-
- return view_func(request, *args, **kwargs)
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Decorator error: {str(e)}")
- return HttpResponse(f"")
- return _wrapped_view
-
-
-@cyberpanel_login_required
-def main_view(request):
- mailUtilities.checkHome()
- return redirect('paypalPremiumPlugin:settings')
-
-
-@cyberpanel_login_required
-@unified_verification_required
-def settings_view(request):
- mailUtilities.checkHome()
- try:
- config = PaypalPremiumPluginConfig.get_config()
- except Exception:
- from django.core.management import call_command
- try:
- call_command('migrate', 'paypalPremiumPlugin', verbosity=0, interactive=False)
- config = PaypalPremiumPluginConfig.get_config()
- except Exception as e:
- return HttpResponse(f"")
-
- access_via = request.session.get('paypal_premium_access_via', '')
- show_payment_ui = access_via not in ('plugin_grant', 'activation_key')
-
- context = {
- 'plugin_name': 'PayPal Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'status': 'Active',
- 'config': config,
- 'has_access': True,
- 'show_payment_ui': show_payment_ui,
- 'access_via_grant_or_key': not show_payment_ui,
- 'patreon_tier': PATREON_TIER,
- 'patreon_url': PATREON_URL,
- 'paypal_me_url': PAYPAL_ME_URL,
- 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'description': 'Configure your PayPal premium plugin settings.',
- }
- proc = httpProc(request, 'paypalPremiumPlugin/settings.html', context, 'admin')
- return proc.render()
-
-
-@cyberpanel_login_required
-@require_http_methods(["POST"])
-def activate_key(request):
- try:
- if request.content_type == 'application/json':
- data = json.loads(request.body)
- else:
- data = request.POST
-
- activation_key = data.get('activation_key', '').strip()
- user_email = data.get('user_email', '').strip()
- if not user_email:
- user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '')
-
- if not activation_key:
- return JsonResponse({'success': False, 'message': 'Activation key is required'}, status=400)
-
- request_data = {'activation_key': activation_key, 'plugin_name': PLUGIN_NAME, 'user_email': user_email}
- response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data)
-
- if response_data.get('success', False) and response_data.get('has_access', False):
- try:
- config = PaypalPremiumPluginConfig.get_config()
- config.activation_key = activation_key
- config.save(update_fields=['activation_key', 'updated_at'])
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: Could not persist activation key: {str(e)}")
-
- return JsonResponse({
- 'success': True,
- 'has_access': True,
- 'message': response_data.get('message', 'Access activated successfully')
- })
-
- return JsonResponse({
- 'success': False,
- 'has_access': False,
- 'message': response_data.get('message', 'Invalid activation key')
- })
-
- except Exception as e:
- logging.writeToFile(f"PayPal Premium Plugin: activate_key error: {str(e)}")
- return JsonResponse({'success': False, 'message': str(e)}, status=500)
-
-
-@cyberpanel_login_required
-@require_http_methods(["POST"])
-def save_payment_method(request):
- try:
- payment_method = request.POST.get('payment_method', 'both')
- if payment_method not in ('patreon', 'paypal', 'both'):
- payment_method = 'both'
- config = PaypalPremiumPluginConfig.get_config()
- config.payment_method = payment_method
- config.save(update_fields=['payment_method', 'updated_at'])
- return JsonResponse({'success': True, 'message': 'Payment method saved'})
- except Exception as e:
- return JsonResponse({'success': False, 'message': str(e)}, status=500)
-
-
-@cyberpanel_login_required
-@unified_verification_required
-def api_status_view(request):
- return JsonResponse({
- 'plugin_name': 'PayPal Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'status': 'active',
- 'payment': 'verified',
- 'verification_method': 'unified'
- })
diff --git a/premiumPlugin/.gitignore b/premiumPlugin/.gitignore
deleted file mode 100644
index 2ef72c88d..000000000
--- a/premiumPlugin/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Security - Never commit secrets
-*.secret
-*_secret*
-patreon_config.py
-.env.patreon
-patreon_secrets.env
diff --git a/premiumPlugin/README-REMOTE-VERIFICATION.md b/premiumPlugin/README-REMOTE-VERIFICATION.md
deleted file mode 100644
index 09decfcd6..000000000
--- a/premiumPlugin/README-REMOTE-VERIFICATION.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Remote Verification Setup
-
-## Overview
-
-This version of the plugin uses **remote verification** - all Patreon API calls happen on YOUR server, not the user's server.
-
-## Benefits
-
-ā
**No secrets in plugin** - Users can see all plugin code, but no credentials
-ā
**Secure** - All Patreon API credentials stay on your server
-ā
**Centralized** - You control access, can revoke, update logic, etc.
-ā
**Public code** - Plugin code can be open source
-
-## Architecture
-
-```
-User's Server Your Server Patreon API
- | | |
- |-- Verify Request ------------> | |
- | |-- Check Membership --> |
- | |<-- Membership Status - |
- |<-- Access Granted/Denied ----- | |
-```
-
-## Setup
-
-### 1. Deploy Verification API
-
-Deploy the verification endpoint to your server:
-- File: `/home/newstargeted.com/api.newstargeted.com/modules/patreon/verify-membership.php`
-- URL: `https://api.newstargeted.com/api/verify-patreon-membership`
-
-### 2. Configure Your Server
-
-Add Patreon credentials to your server's `config.php`:
-
-```php
-define('PATREON_CLIENT_ID', 'your_client_id');
-define('PATREON_CLIENT_SECRET', 'your_client_secret');
-define('PATREON_CREATOR_ACCESS_TOKEN', 'your_access_token');
-```
-
-### 3. Update Plugin
-
-Replace `views.py` with `views_remote.py`:
-
-```bash
-mv views.py views_local.py # Backup local version
-mv views_remote.py views.py # Use remote version
-```
-
-### 4. Configure Plugin URL
-
-Update `REMOTE_VERIFICATION_URL` in `views.py` to point to your server:
-
-```python
-REMOTE_VERIFICATION_URL = 'https://api.newstargeted.com/api/verify-patreon-membership'
-```
-
-## Security Features
-
-- **Rate limiting** - Prevents abuse (60 requests/hour per IP)
-- **HTTPS only** - All communication encrypted
-- **No secrets** - Plugin only makes API calls
-- **Caching** - Reduces Patreon API calls (5 min cache)
-
-## Testing
-
-1. Install plugin on user's server
-2. Try accessing plugin (should show subscription required)
-3. Subscribe to Patreon tier
-4. Access plugin again (should work)
-
-## Migration from Local Verification
-
-If you were using local verification:
-
-1. Keep `views_local.py` as backup
-2. Use `views_remote.py` as `views.py`
-3. Deploy verification API to your server
-4. Update plugin URL in code
diff --git a/premiumPlugin/README.md b/premiumPlugin/README.md
deleted file mode 100644
index 922bffe2e..000000000
--- a/premiumPlugin/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Premium Plugin Example
-
-An example paid plugin for CyberPanel that demonstrates how to implement Patreon subscription-based plugin access.
-
-## Features
-
-- Requires Patreon subscription to "CyberPanel Paid Plugin" tier
-- Users can install the plugin without subscription
-- Plugin functionality is locked until subscription is verified
-- Shows subscription required page when accessed without subscription
-
-## Installation
-
-1. Upload the plugin ZIP file to CyberPanel
-2. Install the plugin from the plugin manager
-3. The plugin will appear in the installed plugins list
-
-## Usage
-
-### For Users Without Subscription
-
-- Plugin can be installed
-- When accessing the plugin, a subscription required page is shown
-- Link to Patreon subscription page is provided
-
-### For Users With Subscription
-
-- Plugin works normally
-- All features are accessible
-- Settings page is available
-
-## Configuration
-
-The plugin checks for Patreon membership via the Patreon API. Make sure to configure:
-
-1. Patreon Client ID
-2. Patreon Client Secret
-3. Patreon Creator ID
-
-These should be set in CyberPanel environment variables or settings.
-
-## Meta.xml Structure
-
-The plugin uses the following meta.xml structure for paid plugins:
-
-```xml
-true
-CyberPanel Paid Plugin
-https://www.patreon.com/c/newstargeted/membership
-```
-
-## Author
-
-master3395
-
-## License
-
-MIT
diff --git a/premiumPlugin/SECURITY.md b/premiumPlugin/SECURITY.md
deleted file mode 100644
index b2df3648e..000000000
--- a/premiumPlugin/SECURITY.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# Security Guidelines for Premium Plugin
-
-## ā ļø IMPORTANT: Never Expose Secrets
-
-This plugin is designed to be **publicly shareable**. It contains **NO secrets** and is safe to publish.
-
-## What's Safe to Share
-
-ā
**Safe to commit:**
-- Plugin code (views.py, urls.py, etc.)
-- Templates (HTML files)
-- meta.xml (no secrets, only tier name and URL)
-- README.md
-- Documentation
-
-ā **Never commit:**
-- Patreon Client Secret
-- Patreon Access Tokens
-- Patreon Refresh Tokens
-- Any hardcoded credentials
-
-## Configuration
-
-All Patreon credentials are configured on the **server side** via:
-- Environment variables
-- Django settings (from environment)
-- Secure config files (not in repository)
-
-## For Your Own Setup
-
-When setting up this plugin on your server:
-
-1. **Do NOT** modify plugin files with your secrets
-2. **Do** configure environment variables on the server
-3. **Do** use Django settings.py (with environment variable fallbacks)
-4. **Do** add any secret config files to .gitignore
-
-## Example Secure Configuration
-
-```python
-# In settings.py (safe to commit)
-PATREON_CLIENT_ID = os.environ.get('PATREON_CLIENT_ID', '')
-PATREON_CLIENT_SECRET = os.environ.get('PATREON_CLIENT_SECRET', '')
-
-# On server (NOT in repo)
-export PATREON_CLIENT_ID="your_actual_secret"
-export PATREON_CLIENT_SECRET="your_actual_secret"
-```
-
-## Verification
-
-Before publishing, verify:
-- [ ] No secrets in plugin files
-- [ ] No secrets in meta.xml
-- [ ] No secrets in README
-- [ ] All credentials use environment variables
-- [ ] .gitignore excludes secret files
diff --git a/premiumPlugin/__init__.py b/premiumPlugin/__init__.py
deleted file mode 100644
index deac71067..000000000
--- a/premiumPlugin/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Premium Plugin Example
-# This is a paid plugin that requires Patreon subscription
-
-default_app_config = 'premiumPlugin.apps.PremiumPluginConfig'
diff --git a/premiumPlugin/api_encryption.py b/premiumPlugin/api_encryption.py
deleted file mode 100644
index 50f8b3d10..000000000
--- a/premiumPlugin/api_encryption.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-AES-256-CBC encryption for plugin <-> api.newstargeted.com communication.
-Key must match PLUGIN_VERIFICATION_CIPHER_KEY in config.php on the API server.
-"""
-import json
-import base64
-import os
-
-CIPHER_KEY_B64 = '1VLPEKTmLGUbIxHUFEtsuVM2MPN1tl8HPFtyJc4dr58='
-ENCRYPTION_ENABLED = True
-
-_ENCRYPTION_CIPHER_KEY = None
-
-
-def _get_key():
- """Get 32-byte AES key from base64."""
- global _ENCRYPTION_CIPHER_KEY
- if _ENCRYPTION_CIPHER_KEY is not None:
- return _ENCRYPTION_CIPHER_KEY
- try:
- key = base64.b64decode(CIPHER_KEY_B64)
- if len(key) == 32:
- _ENCRYPTION_CIPHER_KEY = key
- return key
- except Exception:
- pass
- return None
-
-
-def encrypt_payload(data):
- """Encrypt JSON payload for API request. Returns (body_bytes, headers_dict)."""
- if not ENCRYPTION_ENABLED or not _get_key():
- body = json.dumps(data, separators=(',', ':')).encode('utf-8')
- return body, {'Content-Type': 'application/json'}
- try:
- from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
- from cryptography.hazmat.primitives import padding
- from cryptography.hazmat.backends import default_backend
- key = _get_key()
- plain = json.dumps(data, separators=(',', ':')).encode('utf-8')
- padder = padding.PKCS7(128).padder()
- padded = padder.update(plain) + padder.finalize()
- iv = os.urandom(16)
- cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
- encryptor = cipher.encryptor()
- ciphertext = encryptor.update(padded) + encryptor.finalize()
- payload = base64.b64encode(iv).decode('ascii') + '.' + base64.b64encode(ciphertext).decode('ascii')
- return payload.encode('utf-8'), {'Content-Type': 'text/plain', 'X-Encrypted': '1'}
- except Exception:
- body = json.dumps(data, separators=(',', ':')).encode('utf-8')
- return body, {'Content-Type': 'application/json'}
-
-
-def decrypt_response(body_bytes, content_type='', expect_encrypted=False):
- """Decrypt API response. Handles both encrypted and plain JSON."""
- try:
- body_str = body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else str(body_bytes)
- is_encrypted = (
- expect_encrypted or
- ('text/plain' in content_type and '.' in body_str) or
- ('.' in body_str and body_str.strip() and body_str.strip()[0] not in '{[')
- )
- parts = body_str.strip().split('.', 1)
- if is_encrypted and len(parts) == 2 and ENCRYPTION_ENABLED and _get_key():
- from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
- from cryptography.hazmat.primitives import padding
- from cryptography.hazmat.backends import default_backend
- iv = base64.b64decode(parts[0])
- ciphertext = base64.b64decode(parts[1])
- key = _get_key()
- cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
- decryptor = cipher.decryptor()
- padded = decryptor.update(ciphertext) + decryptor.finalize()
- unpadder = padding.PKCS7(128).unpadder()
- plain = unpadder.update(padded) + unpadder.finalize()
- return json.loads(plain.decode('utf-8'))
- return json.loads(body_str)
- except Exception:
- try:
- return json.loads(body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else body_bytes)
- except Exception:
- return {}
diff --git a/premiumPlugin/apps.py b/premiumPlugin/apps.py
deleted file mode 100644
index 261eb7905..000000000
--- a/premiumPlugin/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-class PremiumPluginConfig(AppConfig):
- name = 'premiumPlugin'
- verbose_name = 'Premium Plugin Example'
diff --git a/premiumPlugin/meta.xml b/premiumPlugin/meta.xml
deleted file mode 100644
index a986da653..000000000
--- a/premiumPlugin/meta.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
- Premium Plugin Example
- Utility
- 1.0.2
- An example paid plugin that requires Patreon subscription to "CyberPanel Paid Plugin" tier. Users can install it but cannot run it without subscription.
- master3395
- https://github.com/master3395/cyberpanel-plugins
- MIT
-
- 3.6+
- 2.2+
- 2.5.5+
-
-
- 2.5.5
- 3.0.0
-
-
- true
- false
-
- true
- CyberPanel Paid Plugin
- https://www.patreon.com/membership/27789984
- https://paypal.me/KimBS?locale.x=en_US&country.x=NO
-
- /plugins/premiumPlugin/
- /plugins/premiumPlugin/settings/
-
diff --git a/premiumPlugin/migrations/0001_initial.py b/premiumPlugin/migrations/0001_initial.py
deleted file mode 100644
index e403a7fbd..000000000
--- a/premiumPlugin/migrations/0001_initial.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated migration for PremiumPluginConfig
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = []
-
- operations = [
- migrations.CreateModel(
- name='PremiumPluginConfig',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('payment_method', models.CharField(choices=[('patreon', 'Patreon Subscription'), ('paypal', 'PayPal Payment'), ('both', 'Check Both (Patreon or PayPal)')], default='both', help_text='Choose which payment method to use for verification.', max_length=10)),
- ('activation_key', models.CharField(blank=True, default='', help_text='Validated activation key - grants access without re-entering.', max_length=64)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('updated_at', models.DateTimeField(auto_now=True)),
- ],
- options={
- 'verbose_name': 'Premium Plugin Configuration',
- 'verbose_name_plural': 'Premium Plugin Configurations',
- },
- ),
- ]
diff --git a/premiumPlugin/migrations/__init__.py b/premiumPlugin/migrations/__init__.py
deleted file mode 100644
index 80dc97892..000000000
--- a/premiumPlugin/migrations/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Premium Plugin migrations
diff --git a/premiumPlugin/models.py b/premiumPlugin/models.py
deleted file mode 100644
index a4396a32a..000000000
--- a/premiumPlugin/models.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-from django.db import models
-
-
-class PremiumPluginConfig(models.Model):
- """Config for Premium Plugin - activation key and payment preference."""
- PAYMENT_METHOD_CHOICES = [
- ('patreon', 'Patreon Subscription'),
- ('paypal', 'PayPal Payment'),
- ('both', 'Check Both (Patreon or PayPal)'),
- ]
- payment_method = models.CharField(
- max_length=10,
- choices=PAYMENT_METHOD_CHOICES,
- default='both',
- help_text="Choose which payment method to use for verification."
- )
- activation_key = models.CharField(
- max_length=64,
- blank=True,
- default='',
- help_text="Validated activation key - grants access without re-entering."
- )
- created_at = models.DateTimeField(auto_now_add=True)
- updated_at = models.DateTimeField(auto_now=True)
-
- class Meta:
- verbose_name = "Premium Plugin Configuration"
- verbose_name_plural = "Premium Plugin Configurations"
-
- def __str__(self):
- return "Premium Plugin Configuration"
-
- @classmethod
- def get_config(cls):
- """Get or create the singleton config instance."""
- config, _ = cls.objects.get_or_create(pk=1)
- return config
-
- def save(self, *args, **kwargs):
- self.pk = 1
- super().save(*args, **kwargs)
diff --git a/premiumPlugin/templates/premiumPlugin/index.html b/premiumPlugin/templates/premiumPlugin/index.html
deleted file mode 100644
index f7ab4e200..000000000
--- a/premiumPlugin/templates/premiumPlugin/index.html
+++ /dev/null
@@ -1,96 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "Premium Plugin Example - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
{% trans "Premium Features" %}
-
- {% for feature in features %}
- {{ feature }}
- {% endfor %}
-
-
-
-{% endblock %}
diff --git a/premiumPlugin/templates/premiumPlugin/settings.html b/premiumPlugin/templates/premiumPlugin/settings.html
deleted file mode 100644
index 59a83d132..000000000
--- a/premiumPlugin/templates/premiumPlugin/settings.html
+++ /dev/null
@@ -1,315 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "Premium Plugin Settings - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-{% endblock %}
diff --git a/premiumPlugin/templates/premiumPlugin/subscription_required.html b/premiumPlugin/templates/premiumPlugin/subscription_required.html
deleted file mode 100644
index cfc11a35a..000000000
--- a/premiumPlugin/templates/premiumPlugin/subscription_required.html
+++ /dev/null
@@ -1,139 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "Payment Required - Premium Plugin" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
{% trans "Premium Plugin Access Required" %}
-
{% trans "This plugin requires payment or subscription to access premium features." %}
-
-
-
-
{% trans "Activate Premium Access" %}
-
{% trans "If you received an activation key, enter it below." %}
-
-
- {% csrf_token %}
-
- {% trans "Activation Key" %}
-
-
-
- {% trans "Activate" %}
-
-
-
-
- {% if payment_method == 'both' %}
-
- {% trans "Current Payment Method:" %} {% trans "Check Both (Patreon or PayPal)" %}
-
- {% elif payment_method == 'patreon' %}
-
- {% trans "Current Payment Method:" %} {% trans "Patreon Subscription Only" %}
-
- {% elif payment_method == 'paypal' %}
-
- {% trans "Current Payment Method:" %} {% trans "PayPal Payment Only" %}
-
- {% endif %}
-
-
-
-
-
{% trans "How it works:" %}
-
- {% trans "Install the plugin (already done)" %}
- {% trans "Enter activation key, subscribe on Patreon, or pay via PayPal" %}
- {% trans "The plugin will automatically unlock" %}
-
-
-
- {% if error %}
-
- {% trans "Error:" %} {{ error }}
-
- {% endif %}
-
-
-
-
-{% endblock %}
diff --git a/premiumPlugin/urls.py b/premiumPlugin/urls.py
deleted file mode 100644
index a9c206dbe..000000000
--- a/premiumPlugin/urls.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from django.urls import path, re_path
-from . import views
-
-app_name = 'premiumPlugin'
-
-urlpatterns = [
- path('', views.main_view, name='main'),
- path('settings/', views.settings_view, name='settings'),
- re_path(r'^activate-key/$', views.activate_key, name='activate_key'),
- path('save-payment-method/', views.save_payment_method, name='save_payment_method'),
- path('api/status/', views.api_status_view, name='api_status'),
-]
diff --git a/premiumPlugin/views.py b/premiumPlugin/views.py
deleted file mode 100644
index fb887850f..000000000
--- a/premiumPlugin/views.py
+++ /dev/null
@@ -1,406 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Premium Plugin Views - Unified Verification (same as contaboAutoSnapshot)
-Supports: Plugin Grants, Activation Key, Patreon, PayPal, AES encryption
-"""
-
-from django.shortcuts import render, redirect
-from django.http import JsonResponse, HttpResponse
-from django.views.decorators.http import require_http_methods
-from plogical.mailUtilities import mailUtilities
-from plogical.httpProc import httpProc
-from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
-from functools import wraps
-import urllib.request
-import urllib.error
-import json
-
-from .models import PremiumPluginConfig
-from . import api_encryption
-
-PLUGIN_NAME = 'premiumPlugin'
-PLUGIN_VERSION = '1.0.2'
-
-REMOTE_VERIFICATION_PATREON_URL = 'https://api.newstargeted.com/api/verify-patreon-membership.php'
-REMOTE_VERIFICATION_PAYPAL_URL = 'https://api.newstargeted.com/api/verify-paypal-payment.php'
-REMOTE_VERIFICATION_PLUGIN_GRANT_URL = 'https://api.newstargeted.com/api/verify-plugin-grant.php'
-REMOTE_ACTIVATION_KEY_URL = 'https://api.newstargeted.com/api/activate-plugin-key.php'
-
-PATREON_TIER = 'CyberPanel Paid Plugin'
-PATREON_URL = 'https://www.patreon.com/membership/27789984'
-PAYPAL_ME_URL = 'https://paypal.me/KimBS?locale.x=en_US&country.x=NO'
-PAYPAL_PAYMENT_LINK = ''
-
-
-def cyberpanel_login_required(view_func):
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- try:
- if not request.session.get('userID'):
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
- return view_func(request, *args, **kwargs)
- except KeyError:
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
- return _wrapped_view
-
-
-def _api_request(url, data, timeout=10):
- """Send encrypted API request and return decoded response dict."""
- try:
- body, extra_headers = api_encryption.encrypt_payload(data)
- headers = {
- 'User-Agent': f'CyberPanel-Plugin/{PLUGIN_VERSION}',
- 'X-Plugin-Name': PLUGIN_NAME
- }
- headers.update(extra_headers)
- req = urllib.request.Request(url, data=body, headers=headers)
- with urllib.request.urlopen(req, timeout=timeout) as response:
- raw = response.read()
- ct = response.headers.get('Content-Type', '')
- expect_enc = extra_headers.get('X-Encrypted') == '1'
- return api_encryption.decrypt_response(raw, ct, expect_encrypted=expect_enc)
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: API request error to {url}: {str(e)}")
- return {}
-
-
-def check_plugin_grant(user_email, user_ip='', domain=''):
- try:
- request_data = {
- 'user_email': user_email or '',
- 'plugin_name': PLUGIN_NAME,
- 'user_ip': user_ip,
- 'domain': domain,
- }
- data = _api_request(REMOTE_VERIFICATION_PLUGIN_GRANT_URL, request_data)
- if data.get('success') and data.get('has_access'):
- return {'has_access': True, 'message': data.get('message', 'Access granted via Plugin Grants')}
- return {'has_access': False, 'message': data.get('message', '')}
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Plugin grant check error: {str(e)}")
- return {'has_access': False, 'message': ''}
-
-
-def check_patreon_membership(user_email, user_ip='', domain=''):
- try:
- request_data = {
- 'user_email': user_email,
- 'plugin_name': PLUGIN_NAME,
- 'plugin_version': PLUGIN_VERSION,
- 'user_ip': user_ip,
- 'domain': domain,
- 'tier_id': '27789984'
- }
- response_data = _api_request(REMOTE_VERIFICATION_PATREON_URL, request_data)
- if response_data.get('success', False):
- return {
- 'has_access': response_data.get('has_access', False),
- 'patreon_tier': response_data.get('patreon_tier', PATREON_TIER),
- 'patreon_url': response_data.get('patreon_url', PATREON_URL),
- 'message': response_data.get('message', 'Access granted'),
- 'error': None
- }
- return {
- 'has_access': False,
- 'patreon_tier': PATREON_TIER,
- 'patreon_url': PATREON_URL,
- 'message': response_data.get('message', 'Patreon subscription required'),
- 'error': response_data.get('error')
- }
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Patreon check error: {str(e)}")
- return {
- 'has_access': False,
- 'patreon_tier': PATREON_TIER,
- 'patreon_url': PATREON_URL,
- 'message': 'Unable to verify Patreon membership.',
- 'error': str(e)
- }
-
-
-def check_paypal_payment(user_email, user_ip='', domain=''):
- try:
- request_data = {
- 'user_email': user_email,
- 'plugin_name': PLUGIN_NAME,
- 'plugin_version': PLUGIN_VERSION,
- 'user_ip': user_ip,
- 'domain': domain,
- 'timestamp': 0,
- }
- import time
- request_data['timestamp'] = int(time.time())
- response_data = _api_request(REMOTE_VERIFICATION_PAYPAL_URL, request_data)
- if response_data.get('success', False):
- return {
- 'has_access': response_data.get('has_access', False),
- 'paypal_me_url': response_data.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': response_data.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': response_data.get('message', 'Access granted'),
- 'error': None
- }
- return {
- 'has_access': False,
- 'paypal_me_url': PAYPAL_ME_URL,
- 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': response_data.get('message', 'PayPal payment required'),
- 'error': response_data.get('error')
- }
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: PayPal check error: {str(e)}")
- return {
- 'has_access': False,
- 'paypal_me_url': PAYPAL_ME_URL,
- 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': 'Unable to verify PayPal payment.',
- 'error': str(e)
- }
-
-
-def unified_verification_required(view_func):
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- try:
- if not request.session.get('userID'):
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
-
- user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '') or getattr(request.user, 'username', '')
-
- try:
- config = PremiumPluginConfig.get_config()
- payment_method = config.payment_method
- except Exception:
- payment_method = 'both'
-
- has_access = False
- verification_result = {}
-
- activation_key = request.GET.get('activation_key') or request.POST.get('activation_key')
- if not activation_key:
- try:
- config = PremiumPluginConfig.get_config()
- activation_key = getattr(config, 'activation_key', '') or ''
- except Exception:
- activation_key = ''
-
- if activation_key:
- try:
- request_data = {
- 'activation_key': activation_key.strip(),
- 'plugin_name': PLUGIN_NAME,
- 'user_email': user_email
- }
- response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data)
- if response_data.get('success', False) and response_data.get('has_access', False):
- has_access = True
- verification_result = {'method': 'activation_key', 'has_access': True, 'message': response_data.get('message', 'Access activated via key')}
- try:
- config = PremiumPluginConfig.get_config()
- config.activation_key = activation_key.strip()
- config.save(update_fields=['activation_key', 'updated_at'])
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Could not persist activation key: {str(e)}")
- elif not response_data.get('success') and activation_key:
- try:
- config = PremiumPluginConfig.get_config()
- if getattr(config, 'activation_key', '') == activation_key.strip():
- config.activation_key = ''
- config.save(update_fields=['activation_key', 'updated_at'])
- except Exception:
- pass
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Activation key check error: {str(e)}")
-
- if not has_access:
- grant_result = check_plugin_grant(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- if grant_result.get('has_access'):
- has_access = True
- verification_result = {'method': 'plugin_grant', 'has_access': True, 'message': grant_result.get('message', 'Access granted via Plugin Grants')}
-
- if not has_access:
- try:
- if payment_method == 'patreon':
- result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- has_access = result.get('has_access', False)
- verification_result = {
- 'method': 'patreon', 'has_access': has_access,
- 'patreon_tier': result.get('patreon_tier', PATREON_TIER),
- 'patreon_url': result.get('patreon_url', PATREON_URL),
- 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': result.get('message', 'Patreon subscription required'),
- 'error': result.get('error')
- }
- elif payment_method == 'paypal':
- result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- has_access = result.get('has_access', False)
- verification_result = {
- 'method': 'paypal', 'has_access': has_access,
- 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL,
- 'paypal_me_url': result.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': result.get('message', 'PayPal payment required'),
- 'error': result.get('error')
- }
- else:
- patreon_result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- paypal_result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host())
- has_access = patreon_result.get('has_access', False) or paypal_result.get('has_access', False)
- verification_result = {
- 'method': 'both', 'has_access': has_access,
- 'patreon_tier': patreon_result.get('patreon_tier', PATREON_TIER),
- 'patreon_url': patreon_result.get('patreon_url', PATREON_URL),
- 'paypal_me_url': paypal_result.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': paypal_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': 'Payment or subscription required' if not has_access else 'Access granted'
- }
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Verification error: {str(e)}")
- has_access = False
- verification_result = {
- 'method': payment_method, 'has_access': False,
- 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL,
- 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'message': 'Unable to verify access.',
- 'error': str(e)
- }
-
- if not has_access:
- context = {
- 'plugin_name': 'Premium Plugin Example',
- 'is_paid': True,
- 'payment_method': payment_method,
- 'verification_result': verification_result,
- 'patreon_tier': verification_result.get('patreon_tier', PATREON_TIER),
- 'patreon_url': verification_result.get('patreon_url', PATREON_URL),
- 'paypal_me_url': verification_result.get('paypal_me_url', PAYPAL_ME_URL),
- 'paypal_payment_link': verification_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK),
- 'message': verification_result.get('message', 'Payment or subscription required'),
- 'error': verification_result.get('error')
- }
- proc = httpProc(request, 'premiumPlugin/subscription_required.html', context, 'admin')
- return proc.render()
-
- if has_access and verification_result:
- request.session['premium_plugin_access_via'] = verification_result.get('method', '')
-
- return view_func(request, *args, **kwargs)
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Decorator error: {str(e)}")
- return HttpResponse(f"")
- return _wrapped_view
-
-
-@cyberpanel_login_required
-def main_view(request):
- mailUtilities.checkHome()
- return redirect('premiumPlugin:settings')
-
-
-@cyberpanel_login_required
-@unified_verification_required
-def settings_view(request):
- mailUtilities.checkHome()
- try:
- config = PremiumPluginConfig.get_config()
- except Exception:
- from django.core.management import call_command
- try:
- call_command('migrate', 'premiumPlugin', verbosity=0, interactive=False)
- config = PremiumPluginConfig.get_config()
- except Exception as e:
- return HttpResponse(f"")
-
- access_via = request.session.get('premium_plugin_access_via', '')
- show_payment_ui = access_via not in ('plugin_grant', 'activation_key')
-
- context = {
- 'plugin_name': 'Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'status': 'Active',
- 'config': config,
- 'has_access': True,
- 'show_payment_ui': show_payment_ui,
- 'access_via_grant_or_key': not show_payment_ui,
- 'patreon_tier': PATREON_TIER,
- 'patreon_url': PATREON_URL,
- 'paypal_me_url': PAYPAL_ME_URL,
- 'paypal_payment_link': PAYPAL_PAYMENT_LINK,
- 'description': 'Configure your premium plugin settings.',
- }
- proc = httpProc(request, 'premiumPlugin/settings.html', context, 'admin')
- return proc.render()
-
-
-@cyberpanel_login_required
-@require_http_methods(["POST"])
-def activate_key(request):
- try:
- if request.content_type == 'application/json':
- data = json.loads(request.body)
- else:
- data = request.POST
-
- activation_key = data.get('activation_key', '').strip()
- user_email = data.get('user_email', '').strip()
- if not user_email:
- user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '')
-
- if not activation_key:
- return JsonResponse({'success': False, 'message': 'Activation key is required'}, status=400)
-
- request_data = {'activation_key': activation_key, 'plugin_name': PLUGIN_NAME, 'user_email': user_email}
- response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data)
-
- if response_data.get('success', False) and response_data.get('has_access', False):
- try:
- config = PremiumPluginConfig.get_config()
- config.activation_key = activation_key
- config.save(update_fields=['activation_key', 'updated_at'])
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: Could not persist activation key: {str(e)}")
-
- return JsonResponse({
- 'success': True,
- 'has_access': True,
- 'message': response_data.get('message', 'Access activated successfully')
- })
-
- return JsonResponse({
- 'success': False,
- 'has_access': False,
- 'message': response_data.get('message', 'Invalid activation key')
- })
-
- except Exception as e:
- logging.writeToFile(f"Premium Plugin: activate_key error: {str(e)}")
- return JsonResponse({'success': False, 'message': str(e)}, status=500)
-
-
-@cyberpanel_login_required
-@require_http_methods(["POST"])
-def save_payment_method(request):
- try:
- payment_method = request.POST.get('payment_method', 'both')
- if payment_method not in ('patreon', 'paypal', 'both'):
- payment_method = 'both'
- config = PremiumPluginConfig.get_config()
- config.payment_method = payment_method
- config.save(update_fields=['payment_method', 'updated_at'])
- return JsonResponse({'success': True, 'message': 'Payment method saved'})
- except Exception as e:
- return JsonResponse({'success': False, 'message': str(e)}, status=500)
-
-
-@cyberpanel_login_required
-@unified_verification_required
-def api_status_view(request):
- return JsonResponse({
- 'plugin_name': 'Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'status': 'active',
- 'subscription': 'active',
- 'verification_method': 'unified'
- })
diff --git a/premiumPlugin/views_remote.py b/premiumPlugin/views_remote.py
deleted file mode 100644
index a4adfaeeb..000000000
--- a/premiumPlugin/views_remote.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Premium Plugin Views - Remote Verification Version
-This version uses remote server verification (no secrets in plugin)
-"""
-
-from django.shortcuts import render, redirect
-from django.http import JsonResponse
-from plogical.mailUtilities import mailUtilities
-from plogical.httpProc import httpProc
-from functools import wraps
-import sys
-import os
-import urllib.request
-import urllib.error
-import json
-
-# Remote verification server (YOUR server, not user's server)
-REMOTE_VERIFICATION_URL = 'https://api.newstargeted.com/api/verify-patreon-membership'
-PLUGIN_NAME = 'premiumPlugin'
-PLUGIN_VERSION = '1.0.0'
-
-def cyberpanel_login_required(view_func):
- """
- Custom decorator that checks for CyberPanel session userID
- """
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- try:
- userID = request.session['userID']
- # User is authenticated via CyberPanel session
- return view_func(request, *args, **kwargs)
- except KeyError:
- # Not logged in, redirect to login
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
- return _wrapped_view
-
-def remote_verification_required(view_func):
- """
- Decorator that checks Patreon membership via remote server
- No secrets stored in plugin - all verification happens on your server
- """
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- # First check login
- try:
- userID = request.session['userID']
- except KeyError:
- from loginSystem.views import loadLoginPage
- return redirect(loadLoginPage)
-
- # Get user email
- user_email = getattr(request.user, 'email', None) if hasattr(request, 'user') and request.user else None
- if not user_email:
- # Try to get from session or username
- user_email = request.session.get('email', '') or getattr(request.user, 'username', '')
-
- # Check membership via remote server
- verification_result = check_remote_membership(user_email, request.META.get('REMOTE_ADDR', ''))
-
- if not verification_result.get('has_access', False):
- # User doesn't have subscription - show subscription required page
- context = {
- 'plugin_name': 'Premium Plugin Example',
- 'is_paid': True,
- 'patreon_tier': verification_result.get('patreon_tier', 'CyberPanel Paid Plugin'),
- 'patreon_url': verification_result.get('patreon_url', 'https://www.patreon.com/c/newstargeted/membership'),
- 'message': verification_result.get('message', 'Patreon subscription required'),
- 'error': verification_result.get('error')
- }
- proc = httpProc(request, 'premiumPlugin/subscription_required.html', context, 'admin')
- return proc.render()
-
- # User has access - proceed with view
- return view_func(request, *args, **kwargs)
-
- return _wrapped_view
-
-def check_remote_membership(user_email, user_ip=''):
- """
- Check Patreon membership via remote verification server
-
- Args:
- user_email: User's email address
- user_ip: User's IP address (for logging/security)
-
- Returns:
- dict: {
- 'has_access': bool,
- 'patreon_tier': str,
- 'patreon_url': str,
- 'message': str,
- 'error': str or None
- }
- """
- try:
- # Prepare request data
- request_data = {
- 'user_email': user_email,
- 'plugin_name': PLUGIN_NAME,
- 'plugin_version': PLUGIN_VERSION,
- 'user_ip': user_ip,
- 'tier_id': '27789984' # CyberPanel Paid Plugin tier ID
- }
-
- # Make request to remote verification server
- req = urllib.request.Request(
- REMOTE_VERIFICATION_URL,
- data=json.dumps(request_data).encode('utf-8'),
- headers={
- 'Content-Type': 'application/json',
- 'User-Agent': f'CyberPanel-Plugin/{PLUGIN_VERSION}',
- 'X-Plugin-Name': PLUGIN_NAME
- }
- )
-
- # Send request with timeout
- try:
- with urllib.request.urlopen(req, timeout=10) as response:
- response_data = json.loads(response.read().decode('utf-8'))
-
- if response_data.get('success', False):
- return {
- 'has_access': response_data.get('has_access', False),
- 'patreon_tier': response_data.get('patreon_tier', 'CyberPanel Paid Plugin'),
- 'patreon_url': response_data.get('patreon_url', 'https://www.patreon.com/c/newstargeted/membership'),
- 'message': response_data.get('message', 'Access granted'),
- 'error': None
- }
- else:
- return {
- 'has_access': False,
- 'patreon_tier': response_data.get('patreon_tier', 'CyberPanel Paid Plugin'),
- 'patreon_url': response_data.get('patreon_url', 'https://www.patreon.com/c/newstargeted/membership'),
- 'message': response_data.get('message', 'Patreon subscription required'),
- 'error': response_data.get('error')
- }
- except urllib.error.HTTPError as e:
- # Server returned error
- error_body = e.read().decode('utf-8') if e.fp else 'Unknown error'
- return {
- 'has_access': False,
- 'patreon_tier': 'CyberPanel Paid Plugin',
- 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership',
- 'message': 'Unable to verify subscription. Please try again later.',
- 'error': f'HTTP {e.code}: {error_body}'
- }
- except urllib.error.URLError as e:
- # Network error
- return {
- 'has_access': False,
- 'patreon_tier': 'CyberPanel Paid Plugin',
- 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership',
- 'message': 'Unable to connect to verification server. Please check your internet connection.',
- 'error': str(e.reason) if hasattr(e, 'reason') else str(e)
- }
- except Exception as e:
- # Other errors
- return {
- 'has_access': False,
- 'patreon_tier': 'CyberPanel Paid Plugin',
- 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership',
- 'message': 'Verification error occurred. Please try again later.',
- 'error': str(e)
- }
-
- except Exception as e:
- import logging
- logging.writeToFile(f"Error in remote membership check: {str(e)}")
- return {
- 'has_access': False,
- 'patreon_tier': 'CyberPanel Paid Plugin',
- 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership',
- 'message': 'Verification error occurred. Please try again later.',
- 'error': str(e)
- }
-
-@cyberpanel_login_required
-@remote_verification_required
-def main_view(request):
- """
- Main view for premium plugin
- Only accessible with Patreon subscription (verified remotely)
- """
- mailUtilities.checkHome()
-
- context = {
- 'plugin_name': 'Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'description': 'This is an example paid plugin. You have access because you are subscribed to Patreon!',
- 'features': [
- 'Premium Feature 1',
- 'Premium Feature 2',
- 'Premium Feature 3',
- 'Advanced Configuration',
- 'Priority Support'
- ]
- }
-
- proc = httpProc(request, 'premiumPlugin/index.html', context, 'admin')
- return proc.render()
-
-@cyberpanel_login_required
-@remote_verification_required
-def settings_view(request):
- """
- Settings page for premium plugin
- Only accessible with Patreon subscription (verified remotely)
- """
- mailUtilities.checkHome()
-
- context = {
- 'plugin_name': 'Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'description': 'Configure your premium plugin settings'
- }
-
- proc = httpProc(request, 'premiumPlugin/settings.html', context, 'admin')
- return proc.render()
-
-@cyberpanel_login_required
-@remote_verification_required
-def api_status_view(request):
- """
- API endpoint for plugin status
- Only accessible with Patreon subscription (verified remotely)
- """
- return JsonResponse({
- 'plugin_name': 'Premium Plugin Example',
- 'version': PLUGIN_VERSION,
- 'status': 'active',
- 'subscription': 'active',
- 'description': 'Premium plugin is active and accessible',
- 'verification_method': 'remote'
- })
diff --git a/testPlugin/OS_COMPATIBILITY.md b/testPlugin/OS_COMPATIBILITY.md
deleted file mode 100644
index b01441843..000000000
--- a/testPlugin/OS_COMPATIBILITY.md
+++ /dev/null
@@ -1,464 +0,0 @@
-# OS Compatibility Guide - CyberPanel Test Plugin
-
-## š Supported Operating Systems
-
-The CyberPanel Test Plugin is designed to work seamlessly across all CyberPanel-supported operating systems with comprehensive multi-OS compatibility.
-
-### ā
Currently Supported OS
-
-| Operating System | Version | Support Status | Python Version | Package Manager | Service Manager |
-|------------------|---------|----------------|----------------|-----------------|-----------------|
-| **Ubuntu** | 22.04 | ā
Full Support | 3.10+ | apt-get | systemctl |
-| **Ubuntu** | 20.04 | ā
Full Support | 3.8+ | apt-get | systemctl |
-| **Debian** | 13 | ā
Full Support | 3.11+ | apt-get | systemctl |
-| **Debian** | 12 | ā
Full Support | 3.10+ | apt-get | systemctl |
-| **Debian** | 11 | ā
Full Support | 3.9+ | apt-get | systemctl |
-| **AlmaLinux** | 10 | ā
Full Support | 3.11+ | dnf | systemctl |
-| **AlmaLinux** | 9 | ā
Full Support | 3.9+ | dnf | systemctl |
-| **AlmaLinux** | 8 | ā
Full Support | 3.6+ | dnf/yum | systemctl |
-| **RockyLinux** | 9 | ā
Full Support | 3.9+ | dnf | systemctl |
-| **RockyLinux** | 8 | ā
Full Support | 3.6+ | dnf | systemctl |
-| **RHEL** | 9 | ā
Full Support | 3.9+ | dnf | systemctl |
-| **RHEL** | 8 | ā
Full Support | 3.6+ | dnf | systemctl |
-| **CloudLinux** | 8 | ā
Full Support | 3.6+ | yum | systemctl |
-| **CentOS** | 9 | ā
Full Support | 3.9+ | dnf | systemctl |
-
-### š§ Third-Party OS Support
-
-| Operating System | Compatibility | Notes |
-|------------------|---------------|-------|
-| **Fedora** | ā
Compatible | Uses dnf package manager |
-| **openEuler** | ā ļø Limited | Community-supported, limited testing |
-| **Other RHEL derivatives** | ā ļø Limited | May work with AlmaLinux/RockyLinux packages |
-
-## š Installation Compatibility
-
-### Automatic OS Detection
-
-The installation script automatically detects your operating system and configures the plugin accordingly:
-
-```bash
-# The script automatically detects:
-# - OS name and version
-# - Python executable path
-# - Package manager (apt-get, dnf, yum)
-# - Service manager (systemctl, service)
-# - Web server (apache2, httpd)
-```
-
-### OS-Specific Configurations
-
-#### Ubuntu/Debian Systems
-```bash
-# Package Manager: apt-get
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: apache2
-# User/Group: cyberpanel:cyberpanel
-```
-
-#### RHEL-based Systems (AlmaLinux, RockyLinux, RHEL, CentOS)
-```bash
-# Package Manager: dnf (RHEL 8+) / yum (RHEL 7)
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: httpd
-# User/Group: cyberpanel:cyberpanel
-```
-
-#### CloudLinux
-```bash
-# Package Manager: yum
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: httpd
-# User/Group: cyberpanel:cyberpanel
-```
-
-## š Python Compatibility
-
-### Supported Python Versions
-
-| Python Version | Ubuntu 22.04 | Ubuntu 20.04 | AlmaLinux 9 | AlmaLinux 8 | RockyLinux 9 | RockyLinux 8 | RHEL 9 | RHEL 8 | CloudLinux 8 |
-|----------------|--------------|--------------|-------------|-------------|--------------|--------------|-------|-------|--------------|
-| **3.6** | ā | ā | ā | ā
| ā | ā
| ā | ā
| ā
|
-| **3.7** | ā | ā | ā | ā
| ā | ā
| ā | ā
| ā
|
-| **3.8** | ā | ā
| ā | ā
| ā | ā
| ā | ā
| ā
|
-| **3.9** | ā
| ā
| ā
| ā
| ā
| ā
| ā
| ā
| ā
|
-| **3.10** | ā
| ā
| ā
| ā
| ā
| ā
| ā
| ā
| ā
|
-| **3.11** | ā
| ā | ā
| ā
| ā
| ā
| ā
| ā
| ā
|
-| **3.12** | ā
| ā | ā
| ā
| ā
| ā
| ā
| ā
| ā
|
-
-### Python Path Detection
-
-The plugin automatically detects the correct Python executable:
-
-```python
-# Detection order:
-1. python3.12
-2. python3.11
-3. python3.10
-4. python3.9
-5. python3.8
-6. python3.7
-7. python3.6
-8. python3
-9. python (fallback)
-```
-
-## š¦ Package Manager Compatibility
-
-### Ubuntu/Debian (apt-get)
-```bash
-# Required packages
-apt-get update
-apt-get install -y python3 python3-pip python3-venv git curl
-apt-get install -y build-essential python3-dev
-
-# Python packages
-pip3 install Django>=2.2,<4.0 django-cors-headers Pillow requests psutil
-```
-
-### RHEL-based (dnf/yum)
-```bash
-# RHEL 8+ (dnf)
-dnf install -y python3 python3-pip python3-devel git curl
-dnf install -y gcc gcc-c++ make
-
-# RHEL 7 (yum)
-yum install -y python3 python3-pip python3-devel git curl
-yum install -y gcc gcc-c++ make
-
-# Python packages
-pip3 install Django>=2.2,<4.0 django-cors-headers Pillow requests psutil
-```
-
-### CloudLinux (yum)
-```bash
-# Required packages
-yum install -y python3 python3-pip python3-devel git curl
-yum install -y gcc gcc-c++ make
-
-# Python packages
-pip3 install Django>=2.2,<4.0 django-cors-headers Pillow requests psutil
-```
-
-## š§ Service Management Compatibility
-
-### systemd (All supported OS)
-```bash
-# Service management commands
-systemctl start lscpd
-systemctl restart lscpd
-systemctl status lscpd
-systemctl enable lscpd
-
-# Web server management
-systemctl start apache2 # Ubuntu/Debian
-systemctl start httpd # RHEL-based
-systemctl restart apache2 # Ubuntu/Debian
-systemctl restart httpd # RHEL-based
-```
-
-### Legacy init.d (Fallback)
-```bash
-# Service management commands
-service lscpd start
-service lscpd restart
-service lscpd status
-
-# Web server management
-service apache2 start # Ubuntu/Debian
-service httpd start # RHEL-based
-```
-
-## š Web Server Compatibility
-
-### Apache2 (Ubuntu/Debian)
-```bash
-# Configuration paths
-/etc/apache2/apache2.conf
-/etc/apache2/sites-available/
-/etc/apache2/sites-enabled/
-
-# Service management
-systemctl start apache2
-systemctl restart apache2
-systemctl status apache2
-```
-
-### HTTPD (RHEL-based)
-```bash
-# Configuration paths
-/etc/httpd/conf/httpd.conf
-/etc/httpd/conf.d/
-
-# Service management
-systemctl start httpd
-systemctl restart httpd
-systemctl status httpd
-```
-
-## š Security Compatibility
-
-### SELinux (RHEL-based systems)
-```bash
-# Check SELinux status
-sestatus
-
-# Set proper context for plugin files
-setsebool -P httpd_can_network_connect 1
-chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/
-```
-
-### AppArmor (Ubuntu/Debian)
-```bash
-# Check AppArmor status
-aa-status
-
-# Allow Apache to access plugin files
-aa-complain apache2
-```
-
-### Firewall Compatibility
-```bash
-# Ubuntu/Debian (ufw)
-ufw allow 8090/tcp
-ufw allow 80/tcp
-ufw allow 443/tcp
-
-# RHEL-based (firewalld)
-firewall-cmd --permanent --add-port=8090/tcp
-firewall-cmd --permanent --add-port=80/tcp
-firewall-cmd --permanent --add-port=443/tcp
-firewall-cmd --reload
-
-# iptables (legacy)
-iptables -A INPUT -p tcp --dport 8090 -j ACCEPT
-iptables -A INPUT -p tcp --dport 80 -j ACCEPT
-iptables -A INPUT -p tcp --dport 443 -j ACCEPT
-```
-
-## š§Ŗ Testing Compatibility
-
-### Run Compatibility Test
-```bash
-# Navigate to plugin directory
-cd /usr/local/CyberCP/testPlugin
-
-# Run compatibility test
-python3 test_os_compatibility.py
-
-# Or make it executable and run
-chmod +x test_os_compatibility.py
-./test_os_compatibility.py
-```
-
-### Test Results
-The compatibility test checks:
-- ā
OS detection and version
-- ā
Python installation and version
-- ā
Package manager availability
-- ā
Service manager functionality
-- ā
Web server configuration
-- ā
File permissions and ownership
-- ā
Network connectivity
-- ā
CyberPanel integration
-
-### Sample Output
-```
-š Testing OS Compatibility for CyberPanel Test Plugin
-============================================================
-
-š Testing OS Detection...
- ā
OS: ubuntu 22.04 (x86_64)
- ā
Supported: True
-
-š Testing Python Detection...
- ā
Python: Python 3.10.12
- ā
Path: /usr/bin/python3
- ā
Pip: /usr/bin/pip3
- ā
Compatible: True
-
-š¦ Testing Package Manager Detection...
- ā
Package Manager: apt-get
- ā
Available: True
-
-š§ Testing Service Manager Detection...
- ā
Service Manager: systemctl
- ā
Web Server: apache2
- ā
Available: True
-
-š Testing Web Server Detection...
- ā
Web Server: apache2
- ā
Installed: True
-
-š Testing File Permissions...
- ā
Plugin Directory: /home/cyberpanel/plugins
- ā
CyberPanel Directory: /usr/local/CyberCP
-
-š Testing Network Connectivity...
- ā
GitHub: True
- ā
Internet: True
-
-ā” Testing CyberPanel Integration...
- ā
CyberPanel Installed: True
- ā
Settings File: True
- ā
URLs File: True
- ā
LSCPD Service: True
-
-============================================================
-š COMPATIBILITY TEST RESULTS
-============================================================
-Total Tests: 8
-ā
Passed: 8
-ā ļø Warnings: 0
-ā Failed: 0
-
-š All tests passed! The plugin is compatible with this OS.
-```
-
-## šØ Troubleshooting
-
-### Common Issues by OS
-
-#### Ubuntu/Debian Issues
-```bash
-# Python not found
-sudo apt-get update
-sudo apt-get install -y python3 python3-pip
-
-# Permission denied
-sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
-sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin
-
-# Service not starting
-sudo systemctl daemon-reload
-sudo systemctl restart lscpd
-```
-
-#### RHEL-based Issues
-```bash
-# Python not found
-sudo dnf install -y python3 python3-pip
-# or
-sudo yum install -y python3 python3-pip
-
-# SELinux issues
-sudo setsebool -P httpd_can_network_connect 1
-sudo chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/
-
-# Permission denied
-sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
-sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin
-```
-
-#### CloudLinux Issues
-```bash
-# Python not found
-sudo yum install -y python3 python3-pip
-
-# CageFS issues
-cagefsctl --enable cyberpanel
-cagefsctl --update
-
-# Permission denied
-sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
-sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin
-```
-
-### Debug Commands
-```bash
-# Check OS information
-cat /etc/os-release
-uname -a
-
-# Check Python installation
-python3 --version
-which python3
-which pip3
-
-# Check services
-systemctl status lscpd
-systemctl status apache2 # Ubuntu/Debian
-systemctl status httpd # RHEL-based
-
-# Check file permissions
-ls -la /home/cyberpanel/plugins/
-ls -la /usr/local/CyberCP/testPlugin/
-
-# Check CyberPanel logs
-tail -f /home/cyberpanel/logs/cyberpanel.log
-tail -f /home/cyberpanel/logs/django.log
-```
-
-## š Installation Checklist
-
-### Pre-Installation
-- [ ] Verify OS is supported
-- [ ] Check Python 3.6+ is installed
-- [ ] Ensure CyberPanel is installed and running
-- [ ] Verify internet connectivity
-- [ ] Check available disk space (minimum 100MB)
-
-### Installation
-- [ ] Download installation script
-- [ ] Run as root user
-- [ ] Monitor installation output
-- [ ] Verify plugin files are created
-- [ ] Check Django settings are updated
-- [ ] Confirm URL configuration is added
-
-### Post-Installation
-- [ ] Test plugin access via web interface
-- [ ] Verify all features work correctly
-- [ ] Check security settings
-- [ ] Run compatibility test
-- [ ] Review installation logs
-
-## š Updates and Maintenance
-
-### Updating the Plugin
-```bash
-# Navigate to plugin directory
-cd /usr/local/CyberCP/testPlugin
-
-# Pull latest changes
-git pull origin main
-
-# Restart services
-sudo systemctl restart lscpd
-sudo systemctl restart apache2 # Ubuntu/Debian
-sudo systemctl restart httpd # RHEL-based
-```
-
-### Uninstalling the Plugin
-```bash
-# Run uninstall script
-sudo ./install.sh --uninstall
-
-# Or manually remove
-sudo rm -rf /usr/local/CyberCP/testPlugin
-sudo rm -f /home/cyberpanel/plugins/testPlugin
-```
-
-## š Support
-
-### OS-Specific Support
-- **Ubuntu/Debian**: Check Ubuntu/Debian documentation
-- **RHEL-based**: Check Red Hat documentation
-- **CloudLinux**: Check CloudLinux documentation
-
-### Plugin Support
-- **GitHub Issues**: https://github.com/cyberpanel/testPlugin/issues
-- **CyberPanel Forums**: https://forums.cyberpanel.net/
-- **Documentation**: https://cyberpanel.net/docs/
-
----
-
-**Last Updated**: September 2025
-**Compatibility Version**: 1.0.0
-**Next Review**: March 2026
diff --git a/testPlugin/SECURITY.md b/testPlugin/SECURITY.md
deleted file mode 100644
index ea6cee1b0..000000000
--- a/testPlugin/SECURITY.md
+++ /dev/null
@@ -1,247 +0,0 @@
-# Security Implementation - CyberPanel Test Plugin
-
-## š Security Overview
-
-The CyberPanel Test Plugin has been designed with **enterprise-grade security** as the top priority. This document outlines all security measures implemented to protect against common web application vulnerabilities and attacks.
-
-## š”ļø Security Features Implemented
-
-### 1. Authentication & Authorization
-- **Admin-only access** required for all plugin functions
-- **User session validation** on every request
-- **Privilege escalation protection**
-- **Role-based access control** (RBAC)
-
-### 2. Rate Limiting & Brute Force Protection
-- **50 requests per 5-minute window** per user
-- **10 test button clicks per minute** limit
-- **Automatic lockout** after 5 failed attempts
-- **15-minute lockout duration**
-- **Progressive punishment system**
-
-### 3. CSRF Protection
-- **HMAC-based CSRF token validation**
-- **Token expiration** after 1 hour
-- **User-specific token generation**
-- **Secure token verification**
-
-### 4. Input Validation & Sanitization
-- **Regex-based input validation**
-- **XSS attack prevention**
-- **SQL injection prevention**
-- **Path traversal protection**
-- **Maximum input length limits** (1000 characters)
-- **Character whitelisting**
-
-### 5. Security Monitoring & Logging
-- **All security events logged** with IP and user agent
-- **Failed attempt tracking** and alerting
-- **Suspicious activity detection**
-- **Real-time security event monitoring**
-- **Comprehensive audit trail**
-
-### 6. HTTP Security Headers
-- **X-Frame-Options: DENY** (clickjacking protection)
-- **X-Content-Type-Options: nosniff**
-- **X-XSS-Protection: 1; mode=block**
-- **Content-Security-Policy (CSP)**
-- **Strict-Transport-Security (HSTS)**
-- **Referrer-Policy: strict-origin-when-cross-origin**
-- **Permissions-Policy**
-
-### 7. Data Isolation & Privacy
-- **User-specific data isolation**
-- **Logs restricted** to user's own activities
-- **Settings isolated** per user
-- **No cross-user data access**
-
-## š Security Middleware
-
-The plugin includes a comprehensive security middleware that performs:
-
-### Request Analysis
-- **Suspicious pattern detection**
-- **SQL injection attempt detection**
-- **XSS attempt detection**
-- **Path traversal attempt detection**
-- **Malicious payload identification**
-
-### Response Protection
-- **Security headers injection**
-- **Content Security Policy enforcement**
-- **Clickjacking protection**
-- **MIME type sniffing prevention**
-
-## šØ Attack Prevention
-
-### OWASP Top 10 Protection
-1. **A01: Broken Access Control** ā
Protected
-2. **A02: Cryptographic Failures** ā
Protected
-3. **A03: Injection** ā
Protected
-4. **A04: Insecure Design** ā
Protected
-5. **A05: Security Misconfiguration** ā
Protected
-6. **A06: Vulnerable Components** ā
Protected
-7. **A07: Authentication Failures** ā
Protected
-8. **A08: Software Integrity Failures** ā
Protected
-9. **A09: Logging Failures** ā
Protected
-10. **A10: Server-Side Request Forgery** ā
Protected
-
-### Specific Attack Vectors Blocked
-- **SQL Injection** - Regex pattern matching + parameterized queries
-- **Cross-Site Scripting (XSS)** - Input sanitization + CSP headers
-- **Cross-Site Request Forgery (CSRF)** - HMAC token validation
-- **Brute Force Attacks** - Rate limiting + account lockout
-- **Path Traversal** - Pattern detection + input validation
-- **Clickjacking** - X-Frame-Options header
-- **Session Hijacking** - Secure session management
-- **Privilege Escalation** - Role-based access control
-
-## š Security Metrics
-
-- **15+ Security Features** implemented
-- **99% Attack Prevention** rate
-- **24/7 Security Monitoring** active
-- **0 Known Vulnerabilities** in current version
-- **Enterprise-grade** security standards
-
-## š§ Security Configuration
-
-### Rate Limiting Settings
-```python
-RATE_LIMIT_WINDOW = 300 # 5 minutes
-MAX_REQUESTS_PER_WINDOW = 50
-MAX_FAILED_ATTEMPTS = 5
-LOCKOUT_DURATION = 900 # 15 minutes
-```
-
-### Input Validation Settings
-```python
-SAFE_STRING_PATTERN = re.compile(r'^[a-zA-Z0-9\s\-_.,!?@#$%^&*()+=\[\]{}|\\:";\'<>?/~`]*$')
-MAX_MESSAGE_LENGTH = 1000
-```
-
-### CSRF Token Settings
-```python
-TOKEN_EXPIRATION = 3600 # 1 hour
-HMAC_ALGORITHM = 'sha256'
-```
-
-## š Security Best Practices
-
-### For Developers
-1. **Always validate input** before processing
-2. **Use parameterized queries** for database operations
-3. **Implement proper error handling** without information disclosure
-4. **Log security events** for monitoring
-5. **Keep dependencies updated**
-6. **Use HTTPS** in production
-7. **Implement proper session management**
-
-### For Administrators
-1. **Keep CyberPanel updated**
-2. **Use strong, unique passwords**
-3. **Enable 2FA** on admin accounts
-4. **Regularly review security logs**
-5. **Monitor failed login attempts**
-6. **Use HTTPS** in production environments
-7. **Regular security audits**
-
-## š Security Monitoring
-
-### Logged Events
-- **Authentication attempts** (successful and failed)
-- **Authorization failures**
-- **Rate limit violations**
-- **Suspicious request patterns**
-- **Input validation failures**
-- **Security policy violations**
-- **System errors and exceptions**
-
-### Monitoring Dashboard
-Access the security information page at: `/testPlugin/security/`
-
-## š ļø Security Testing
-
-### Automated Tests
-- **Unit tests** for all security functions
-- **Integration tests** for security middleware
-- **Penetration testing** scenarios
-- **Vulnerability scanning**
-
-### Manual Testing
-- **OWASP ZAP** security testing
-- **Burp Suite** penetration testing
-- **Manual security review**
-- **Code security audit**
-
-## š Security Checklist
-
-- [x] Authentication implemented
-- [x] Authorization implemented
-- [x] CSRF protection enabled
-- [x] Rate limiting configured
-- [x] Input validation active
-- [x] XSS protection enabled
-- [x] SQL injection protection
-- [x] Security headers configured
-- [x] Logging implemented
-- [x] Error handling secure
-- [x] Session management secure
-- [x] Data isolation implemented
-- [x] Security monitoring active
-
-## šØ Incident Response
-
-### Security Incident Procedure
-1. **Immediate Response**
- - Block suspicious IP addresses
- - Review security logs
- - Assess impact
-
-2. **Investigation**
- - Analyze attack vectors
- - Identify compromised accounts
- - Document findings
-
-3. **Recovery**
- - Patch vulnerabilities
- - Reset compromised accounts
- - Update security measures
-
-4. **Post-Incident**
- - Review security policies
- - Update monitoring rules
- - Conduct security training
-
-## š Security Contact
-
-For security-related issues or vulnerability reports:
-
-- **Email**: security@cyberpanel.net
-- **GitHub**: Create a private security issue
-- **Response Time**: Within 24-48 hours
-
-## š Security Updates
-
-Security is an ongoing process. Regular updates include:
-
-- **Security patches** for vulnerabilities
-- **Enhanced monitoring** capabilities
-- **Improved detection** algorithms
-- **Updated security policies**
-- **New protection mechanisms**
-
-## š Additional Resources
-
-- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
-- [Django Security](https://docs.djangoproject.com/en/stable/topics/security/)
-- [CyberPanel Security](https://cyberpanel.net/docs/)
-- [Web Application Security](https://cheatsheetseries.owasp.org/)
-
----
-
-**Security Note**: This plugin implements enterprise-grade security measures. However, security is an ongoing process. Regular updates and monitoring are essential to maintain the highest security standards.
-
-**Last Updated**: December 2024
-**Security Version**: 1.0.0
-**Next Review**: March 2025
diff --git a/testPlugin/__init__.py b/testPlugin/__init__.py
deleted file mode 100644
index 695a722b6..000000000
--- a/testPlugin/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# -*- coding: utf-8 -*-
-default_app_config = 'testPlugin.apps.TestPluginConfig'
diff --git a/testPlugin/admin.py b/testPlugin/admin.py
deleted file mode 100644
index cd858aeea..000000000
--- a/testPlugin/admin.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-from django.contrib import admin
-from .models import TestPluginSettings, TestPluginLog
-
-
-@admin.register(TestPluginSettings)
-class TestPluginSettingsAdmin(admin.ModelAdmin):
- list_display = ['user', 'plugin_enabled', 'test_count', 'last_test_time']
- list_filter = ['plugin_enabled', 'last_test_time']
- search_fields = ['user__username', 'custom_message']
- readonly_fields = ['last_test_time']
-
-
-@admin.register(TestPluginLog)
-class TestPluginLogAdmin(admin.ModelAdmin):
- list_display = ['timestamp', 'action', 'message', 'user']
- list_filter = ['action', 'timestamp', 'user']
- search_fields = ['action', 'message', 'user__username']
- readonly_fields = ['timestamp']
- date_hierarchy = 'timestamp'
diff --git a/testPlugin/apps.py b/testPlugin/apps.py
deleted file mode 100644
index ae29de970..000000000
--- a/testPlugin/apps.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-from django.apps import AppConfig
-
-
-class TestPluginConfig(AppConfig):
- name = 'testPlugin'
- verbose_name = 'Test Plugin'
-
- def ready(self):
- # Import signal handlers
- import testPlugin.signals
diff --git a/testPlugin/install.sh b/testPlugin/install.sh
deleted file mode 100644
index b87eb2140..000000000
--- a/testPlugin/install.sh
+++ /dev/null
@@ -1,580 +0,0 @@
-#!/bin/bash
-
-# Test Plugin Installation Script for CyberPanel
-# Multi-OS Compatible Installation Script
-# Supports: Ubuntu, Debian, AlmaLinux, RockyLinux, RHEL, CloudLinux, CentOS
-
-set -e
-
-# Colors for output
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
-NC='\033[0m' # No Color
-
-# Configuration
-PLUGIN_NAME="testPlugin"
-PLUGIN_DIR="/home/cyberpanel/plugins"
-CYBERPANEL_DIR="/usr/local/CyberCP"
-GITHUB_REPO="https://github.com/cyberpanel/testPlugin.git"
-TEMP_DIR="/tmp/cyberpanel_plugin_install"
-
-# OS Detection Variables
-OS_NAME=""
-OS_VERSION=""
-OS_ARCH=""
-PYTHON_CMD=""
-PIP_CMD=""
-SERVICE_CMD=""
-WEB_SERVER=""
-
-# Function to print colored output
-print_status() {
- echo -e "${BLUE}[INFO]${NC} $1"
-}
-
-print_success() {
- echo -e "${GREEN}[SUCCESS]${NC} $1"
-}
-
-print_warning() {
- echo -e "${YELLOW}[WARNING]${NC} $1"
-}
-
-print_error() {
- echo -e "${RED}[ERROR]${NC} $1"
-}
-
-# Function to detect operating system
-detect_os() {
- print_status "Detecting operating system..."
-
- if [ -f /etc/os-release ]; then
- . /etc/os-release
- OS_NAME="$ID"
- OS_VERSION="$VERSION_ID"
- elif [ -f /etc/redhat-release ]; then
- OS_NAME="rhel"
- OS_VERSION=$(cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+' | head -1)
- elif [ -f /etc/debian_version ]; then
- OS_NAME="debian"
- OS_VERSION=$(cat /etc/debian_version)
- else
- print_error "Unable to detect operating system"
- exit 1
- fi
-
- # Detect architecture
- OS_ARCH=$(uname -m)
-
- print_success "Detected: $OS_NAME $OS_VERSION ($OS_ARCH)"
-
- # Set OS-specific configurations
- configure_os_specific
-}
-
-# Function to configure OS-specific settings
-configure_os_specific() {
- case "$OS_NAME" in
- "ubuntu"|"debian")
- PYTHON_CMD="python3"
- PIP_CMD="pip3"
- SERVICE_CMD="systemctl"
- WEB_SERVER="apache2"
- ;;
- "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux")
- PYTHON_CMD="python3"
- PIP_CMD="pip3"
- SERVICE_CMD="systemctl"
- WEB_SERVER="httpd"
- ;;
- *)
- print_warning "Unknown OS: $OS_NAME. Using default configurations."
- PYTHON_CMD="python3"
- PIP_CMD="pip3"
- SERVICE_CMD="systemctl"
- WEB_SERVER="httpd"
- ;;
- esac
-
- print_status "Using Python: $PYTHON_CMD"
- print_status "Using Pip: $PIP_CMD"
- print_status "Using Service Manager: $SERVICE_CMD"
- print_status "Using Web Server: $WEB_SERVER"
-}
-
-# Function to check if running as root
-check_root() {
- if [[ $EUID -ne 0 ]]; then
- print_error "This script must be run as root"
- exit 1
- fi
-}
-
-# Function to check if CyberPanel is installed
-check_cyberpanel() {
- if [ ! -d "$CYBERPANEL_DIR" ]; then
- print_error "CyberPanel is not installed at $CYBERPANEL_DIR"
- print_error "Please install CyberPanel first: https://cyberpanel.net/docs/"
- exit 1
- fi
-
- # Check if CyberPanel is running
- if ! $SERVICE_CMD is-active --quiet lscpd; then
- print_warning "CyberPanel service (lscpd) is not running. Starting it..."
- $SERVICE_CMD start lscpd
- fi
-
- print_success "CyberPanel installation verified"
-}
-
-# Function to check Python installation
-check_python() {
- print_status "Checking Python installation..."
-
- if ! command -v $PYTHON_CMD &> /dev/null; then
- print_error "Python3 is not installed. Installing..."
- install_python
- fi
-
- # Check Python version (require 3.6+)
- PYTHON_VERSION=$($PYTHON_CMD -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")
- PYTHON_MAJOR=$(echo $PYTHON_VERSION | cut -d. -f1)
- PYTHON_MINOR=$(echo $PYTHON_VERSION | cut -d. -f2)
-
- if [ "$PYTHON_MAJOR" -lt 3 ] || ([ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 6 ]); then
- print_error "Python 3.6+ is required. Found: $PYTHON_VERSION"
- exit 1
- fi
-
- print_success "Python $PYTHON_VERSION is available"
-}
-
-# Function to install Python if needed
-install_python() {
- case "$OS_NAME" in
- "ubuntu"|"debian")
- apt-get update
- apt-get install -y python3 python3-pip python3-venv
- ;;
- "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux")
- if command -v dnf &> /dev/null; then
- dnf install -y python3 python3-pip
- elif command -v yum &> /dev/null; then
- yum install -y python3 python3-pip
- else
- print_error "No package manager found (dnf/yum)"
- exit 1
- fi
- ;;
- esac
-}
-
-# Function to check pip installation
-check_pip() {
- print_status "Checking pip installation..."
-
- if ! command -v $PIP_CMD &> /dev/null; then
- print_error "pip3 is not installed. Installing..."
- install_pip
- fi
-
- print_success "pip3 is available"
-}
-
-# Function to install pip if needed
-install_pip() {
- case "$OS_NAME" in
- "ubuntu"|"debian")
- apt-get install -y python3-pip
- ;;
- "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux")
- if command -v dnf &> /dev/null; then
- dnf install -y python3-pip
- elif command -v yum &> /dev/null; then
- yum install -y python3-pip
- fi
- ;;
- esac
-}
-
-# Function to check required packages
-check_packages() {
- print_status "Checking required packages..."
-
- # Check for git
- if ! command -v git &> /dev/null; then
- print_error "git is not installed. Installing..."
- install_git
- fi
-
- # Check for curl
- if ! command -v curl &> /dev/null; then
- print_error "curl is not installed. Installing..."
- install_curl
- fi
-
- print_success "All required packages are available"
-}
-
-# Function to install git
-install_git() {
- case "$OS_NAME" in
- "ubuntu"|"debian")
- apt-get update
- apt-get install -y git
- ;;
- "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux")
- if command -v dnf &> /dev/null; then
- dnf install -y git
- elif command -v yum &> /dev/null; then
- yum install -y git
- fi
- ;;
- esac
-}
-
-# Function to install curl
-install_curl() {
- case "$OS_NAME" in
- "ubuntu"|"debian")
- apt-get update
- apt-get install -y curl
- ;;
- "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux")
- if command -v dnf &> /dev/null; then
- dnf install -y curl
- elif command -v yum &> /dev/null; then
- yum install -y curl
- fi
- ;;
- esac
-}
-
-# Function to create plugin directory
-create_plugin_directory() {
- print_status "Creating plugin directory structure..."
-
- # Create main plugin directory
- mkdir -p "$PLUGIN_DIR"
-
- # Create CyberPanel plugin directory
- mkdir -p "$CYBERPANEL_DIR/$PLUGIN_NAME"
-
- # Set proper permissions
- chown -R cyberpanel:cyberpanel "$PLUGIN_DIR" 2>/dev/null || chown -R root:root "$PLUGIN_DIR"
- chmod -R 755 "$PLUGIN_DIR"
-
- chown -R cyberpanel:cyberpanel "$CYBERPANEL_DIR/$PLUGIN_NAME" 2>/dev/null || chown -R root:root "$CYBERPANEL_DIR/$PLUGIN_NAME"
- chmod -R 755 "$CYBERPANEL_DIR/$PLUGIN_NAME"
-
- print_success "Plugin directory structure created"
-}
-
-# Function to download plugin
-download_plugin() {
- print_status "Downloading plugin from GitHub..."
-
- # Clean up temp directory
- rm -rf "$TEMP_DIR"
- mkdir -p "$TEMP_DIR"
-
- # Clone the repository
- if ! git clone "$GITHUB_REPO" "$TEMP_DIR"; then
- print_error "Failed to download plugin from GitHub"
- print_error "Please check your internet connection and try again"
- exit 1
- fi
-
- print_success "Plugin downloaded successfully"
-}
-
-# Function to install plugin files
-install_plugin_files() {
- print_status "Installing plugin files..."
-
- # Copy plugin files
- cp -r "$TEMP_DIR"/* "$CYBERPANEL_DIR/$PLUGIN_NAME/"
-
- # Create symlink
- ln -sf "$CYBERPANEL_DIR/$PLUGIN_NAME" "$PLUGIN_DIR/$PLUGIN_NAME"
-
- # Set proper ownership and permissions
- chown -R cyberpanel:cyberpanel "$CYBERPANEL_DIR/$PLUGIN_NAME" 2>/dev/null || chown -R root:root "$CYBERPANEL_DIR/$PLUGIN_NAME"
- chmod -R 755 "$CYBERPANEL_DIR/$PLUGIN_NAME"
-
- # Make scripts executable
- chmod +x "$CYBERPANEL_DIR/$PLUGIN_NAME/install.sh" 2>/dev/null || true
-
- print_success "Plugin files installed"
-}
-
-# Function to update Django settings
-update_django_settings() {
- print_status "Updating Django settings..."
-
- SETTINGS_FILE="$CYBERPANEL_DIR/cyberpanel/settings.py"
-
- # Check if plugin is already in INSTALLED_APPS
- if ! grep -q "'$PLUGIN_NAME'" "$SETTINGS_FILE"; then
- # Add plugin to INSTALLED_APPS
- sed -i "/INSTALLED_APPS = \[/a\ '$PLUGIN_NAME'," "$SETTINGS_FILE"
- print_success "Added $PLUGIN_NAME to INSTALLED_APPS"
- else
- print_warning "$PLUGIN_NAME already in INSTALLED_APPS"
- fi
-}
-
-# Function to update URL configuration
-update_urls() {
- print_status "Updating URL configuration..."
-
- URLS_FILE="$CYBERPANEL_DIR/cyberpanel/urls.py"
-
- # Check if plugin URLs are already included
- if ! grep -q "path(\"$PLUGIN_NAME/\"" "$URLS_FILE"; then
- # Add plugin URLs
- sed -i "/urlpatterns = \[/a\ path(\"$PLUGIN_NAME/\", include(\"$PLUGIN_NAME.urls\"))," "$URLS_FILE"
- print_success "Added $PLUGIN_NAME URLs"
- else
- print_warning "$PLUGIN_NAME URLs already configured"
- fi
-}
-
-# Function to run database migrations
-run_migrations() {
- print_status "Running database migrations..."
-
- cd "$CYBERPANEL_DIR"
-
- # Create migrations
- if ! $PYTHON_CMD manage.py makemigrations $PLUGIN_NAME; then
- print_warning "No migrations to create for $PLUGIN_NAME"
- fi
-
- # Apply migrations
- if ! $PYTHON_CMD manage.py migrate $PLUGIN_NAME; then
- print_warning "No migrations to apply for $PLUGIN_NAME"
- fi
-
- print_success "Database migrations completed"
-}
-
-# Function to collect static files
-collect_static() {
- print_status "Collecting static files..."
-
- cd "$CYBERPANEL_DIR"
-
- if ! $PYTHON_CMD manage.py collectstatic --noinput; then
- print_warning "Static file collection failed, but continuing..."
- else
- print_success "Static files collected"
- fi
-}
-
-# Function to restart services
-restart_services() {
- print_status "Restarting CyberPanel services..."
-
- # Restart lscpd
- if $SERVICE_CMD is-active --quiet lscpd; then
- $SERVICE_CMD restart lscpd
- print_success "lscpd service restarted"
- else
- print_warning "lscpd service not running"
- fi
-
- # Restart web server
- if $SERVICE_CMD is-active --quiet $WEB_SERVER; then
- $SERVICE_CMD restart $WEB_SERVER
- print_success "$WEB_SERVER service restarted"
- else
- print_warning "$WEB_SERVER service not running"
- fi
-
- # Additional service restart for different OS
- case "$OS_NAME" in
- "ubuntu"|"debian")
- if $SERVICE_CMD is-active --quiet cyberpanel; then
- $SERVICE_CMD restart cyberpanel
- print_success "cyberpanel service restarted"
- fi
- ;;
- "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux")
- if $SERVICE_CMD is-active --quiet cyberpanel; then
- $SERVICE_CMD restart cyberpanel
- print_success "cyberpanel service restarted"
- fi
- ;;
- esac
-}
-
-# Function to verify installation
-verify_installation() {
- print_status "Verifying installation..."
-
- # Check if plugin directory exists
- if [ ! -d "$CYBERPANEL_DIR/$PLUGIN_NAME" ]; then
- print_error "Plugin directory not found"
- return 1
- fi
-
- # Check if symlink exists
- if [ ! -L "$PLUGIN_DIR/$PLUGIN_NAME" ]; then
- print_error "Plugin symlink not found"
- return 1
- fi
-
- # Check if meta.xml exists
- if [ ! -f "$CYBERPANEL_DIR/$PLUGIN_NAME/meta.xml" ]; then
- print_error "Plugin meta.xml not found"
- return 1
- fi
-
- print_success "Installation verified successfully"
- return 0
-}
-
-# Function to display installation summary
-display_summary() {
- echo ""
- echo "=========================================="
- print_success "Test Plugin Installation Complete!"
- echo "=========================================="
- echo "Plugin Name: $PLUGIN_NAME"
- echo "Installation Directory: $CYBERPANEL_DIR/$PLUGIN_NAME"
- echo "Plugin Directory: $PLUGIN_DIR/$PLUGIN_NAME"
- echo "Access URL: https://your-domain:8090/testPlugin/"
- echo "Operating System: $OS_NAME $OS_VERSION ($OS_ARCH)"
- echo "Python Version: $($PYTHON_CMD --version)"
- echo ""
- echo "Features Installed:"
- echo "ā Enable/Disable Toggle"
- echo "ā Test Button with Popup Messages"
- echo "ā Settings Page"
- echo "ā Activity Logs"
- echo "ā Inline Integration"
- echo "ā Complete Documentation"
- echo "ā Official CyberPanel Guide"
- echo "ā Advanced Development Guide"
- echo "ā Enterprise-Grade Security"
- echo "ā Brute Force Protection"
- echo "ā CSRF Protection"
- echo "ā XSS Prevention"
- echo "ā SQL Injection Protection"
- echo "ā Rate Limiting"
- echo "ā Security Monitoring"
- echo "ā Security Information Page"
- echo "ā Multi-OS Compatibility"
- echo ""
- echo "Supported Operating Systems:"
- echo "ā Ubuntu 22.04, 20.04"
- echo "ā Debian (compatible)"
- echo "ā AlmaLinux 8, 9, 10"
- echo "ā RockyLinux 8, 9"
- echo "ā RHEL 8, 9"
- echo "ā CloudLinux 8"
- echo "ā CentOS 9"
- echo ""
- echo "To uninstall, run: $0 --uninstall"
- echo "=========================================="
-}
-
-# Function to uninstall plugin
-uninstall_plugin() {
- print_status "Uninstalling $PLUGIN_NAME..."
-
- # Remove plugin files
- rm -rf "$CYBERPANEL_DIR/$PLUGIN_NAME"
- rm -f "$PLUGIN_DIR/$PLUGIN_NAME"
-
- # Remove from Django settings
- SETTINGS_FILE="$CYBERPANEL_DIR/cyberpanel/settings.py"
- if [ -f "$SETTINGS_FILE" ]; then
- sed -i "/'$PLUGIN_NAME',/d" "$SETTINGS_FILE"
- print_success "Removed $PLUGIN_NAME from INSTALLED_APPS"
- fi
-
- # Remove from URLs
- URLS_FILE="$CYBERPANEL_DIR/cyberpanel/urls.py"
- if [ -f "$URLS_FILE" ]; then
- sed -i "/path(\"$PLUGIN_NAME\/\"/d" "$URLS_FILE"
- print_success "Removed $PLUGIN_NAME URLs"
- fi
-
- # Restart services
- restart_services
-
- print_success "Plugin uninstalled successfully"
-}
-
-# Main installation function
-install_plugin() {
- print_status "Starting Test Plugin installation..."
-
- # Detect OS
- detect_os
-
- # Check requirements
- check_root
- check_cyberpanel
- check_python
- check_pip
- check_packages
-
- # Install plugin
- create_plugin_directory
- download_plugin
- install_plugin_files
- update_django_settings
- update_urls
- run_migrations
- collect_static
- restart_services
-
- # Verify installation
- if verify_installation; then
- display_summary
- else
- print_error "Installation verification failed"
- exit 1
- fi
-}
-
-# Main script logic
-main() {
- case "${1:-}" in
- "--uninstall")
- check_root
- uninstall_plugin
- ;;
- "--help"|"-h")
- echo "Usage: $0 [OPTIONS]"
- echo "Options:"
- echo " --uninstall Uninstall the plugin"
- echo " --help, -h Show this help message"
- echo ""
- echo "Supported Operating Systems:"
- echo " Ubuntu 22.04, 20.04"
- echo " Debian (compatible)"
- echo " AlmaLinux 8, 9, 10"
- echo " RockyLinux 8, 9"
- echo " RHEL 8, 9"
- echo " CloudLinux 8"
- echo " CentOS 9"
- ;;
- "")
- install_plugin
- ;;
- *)
- print_error "Unknown option: $1"
- echo "Use --help for usage information"
- exit 1
- ;;
- esac
-}
-
-# Run main function
-main "$@"
\ No newline at end of file
diff --git a/testPlugin/meta.xml b/testPlugin/meta.xml
deleted file mode 100644
index 76993172a..000000000
--- a/testPlugin/meta.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
- Test Plugin
- Utility
- 1.0.0
- A comprehensive test plugin for CyberPanel with enable/disable functionality, test button, popup messages, and inline integration
- usmannasir
- https://github.com/cyberpanel/testPlugin
- MIT
-
- 3.6+
- 2.2+
-
-
- true
- false
-
-
- true
- true
- true
- true
-
- /plugins/testPlugin/
- /plugins/testPlugin/settings/
-
diff --git a/testPlugin/middleware.py b/testPlugin/middleware.py
deleted file mode 100644
index 7d0bd6cc2..000000000
--- a/testPlugin/middleware.py
+++ /dev/null
@@ -1,208 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Security middleware for the Test Plugin
-Provides additional security measures and monitoring
-"""
-import time
-import hashlib
-from django.http import JsonResponse
-from django.core.cache import cache
-from django.conf import settings
-from .security import SecurityManager
-
-
-class TestPluginSecurityMiddleware:
- """
- Security middleware for the Test Plugin
- Provides additional protection against various attacks
- """
-
- def __init__(self, get_response):
- self.get_response = get_response
-
- def __call__(self, request):
- # Only apply security measures to testPlugin URLs
- if not request.path.startswith('/testPlugin/'):
- return self.get_response(request)
-
- # Security checks
- if not self._security_checks(request):
- return JsonResponse({
- 'status': 0,
- 'error_message': 'Security violation detected. Access denied.'
- }, status=403)
-
- response = self.get_response(request)
-
- # Add security headers
- self._add_security_headers(response)
-
- return response
-
- def _security_checks(self, request):
- """Perform security checks on the request"""
-
- # Check for suspicious patterns
- if self._is_suspicious_request(request):
- SecurityManager.log_security_event(request, "Suspicious request pattern detected", "suspicious_request")
- return False
-
- # Check for SQL injection attempts
- if self._has_sql_injection_patterns(request):
- SecurityManager.log_security_event(request, "SQL injection attempt detected", "sql_injection")
- return False
-
- # Check for XSS attempts
- if self._has_xss_patterns(request):
- SecurityManager.log_security_event(request, "XSS attempt detected", "xss_attempt")
- return False
-
- # Check for path traversal attempts
- if self._has_path_traversal_patterns(request):
- SecurityManager.log_security_event(request, "Path traversal attempt detected", "path_traversal")
- return False
-
- return True
-
- def _is_suspicious_request(self, request):
- """Check for suspicious request patterns"""
- suspicious_patterns = [
- '..', '//', '\\', 'cmd', 'exec', 'system', 'eval',
- 'base64', 'decode', 'encode', 'hex', 'binary',
- 'union', 'select', 'insert', 'update', 'delete',
- 'drop', 'create', 'alter', 'grant', 'revoke'
- ]
-
- # Check URL
- url_lower = request.path.lower()
- for pattern in suspicious_patterns:
- if pattern in url_lower:
- return True
-
- # Check query parameters
- for key, value in request.GET.items():
- if isinstance(value, str):
- value_lower = value.lower()
- for pattern in suspicious_patterns:
- if pattern in value_lower:
- return True
-
- # Check POST data
- if request.method == 'POST':
- for key, value in request.POST.items():
- if isinstance(value, str):
- value_lower = value.lower()
- for pattern in suspicious_patterns:
- if pattern in value_lower:
- return True
-
- return False
-
- def _has_sql_injection_patterns(self, request):
- """Check for SQL injection patterns"""
- sql_patterns = [
- "'", '"', ';', '--', '/*', '*/', 'xp_', 'sp_',
- 'union', 'select', 'insert', 'update', 'delete',
- 'drop', 'create', 'alter', 'exec', 'execute',
- 'waitfor', 'delay', 'benchmark', 'sleep'
- ]
-
- # Check all request data
- all_data = []
- all_data.extend(request.GET.values())
- all_data.extend(request.POST.values())
-
- for value in all_data:
- if isinstance(value, str):
- value_lower = value.lower()
- for pattern in sql_patterns:
- if pattern in value_lower:
- return True
-
- return False
-
- def _has_xss_patterns(self, request):
- """Check for XSS patterns"""
- xss_patterns = [
- '', '</script>')
- data = data.replace('javascript:', '')
- data = data.replace('onload=', '')
- data = data.replace('onerror=', '')
- data = data.replace('onclick=', '')
- data = data.replace('onmouseover=', '')
- # Remove null bytes
- data = data.replace('\x00', '')
- # Limit length
- data = data[:SecurityManager.MAX_MESSAGE_LENGTH]
-
- return data
-
- @staticmethod
- def log_security_event(request, message, event_type="security"):
- """Log security-related events"""
- try:
- user_id = request.user.id if request.user.is_authenticated else None
- ip_address = request.META.get('REMOTE_ADDR', 'unknown')
- user_agent = request.META.get('HTTP_USER_AGENT', 'unknown')
-
- TestPluginLog.objects.create(
- user_id=user_id,
- action=event_type,
- message=f"[SECURITY] {message} | IP: {ip_address} | UA: {user_agent[:100]}"
- )
- except Exception:
- # Don't let logging errors break the application
- pass
-
- @staticmethod
- def generate_csrf_token(request):
- """Generate a secure CSRF token"""
- if hasattr(request, 'csrf_token'):
- return request.csrf_token
-
- # Fallback CSRF token generation
- secret = getattr(settings, 'SECRET_KEY', 'fallback-secret')
- timestamp = str(int(time.time()))
- user_id = str(request.user.id) if request.user.is_authenticated else 'anonymous'
-
- token_data = f"{user_id}:{timestamp}"
- token = hmac.new(
- secret.encode(),
- token_data.encode(),
- hashlib.sha256
- ).hexdigest()
-
- return f"{token}:{timestamp}"
-
- @staticmethod
- def verify_csrf_token(request, token):
- """Verify CSRF token"""
- if hasattr(request, 'csrf_token'):
- return request.csrf_token == token
-
- try:
- secret = getattr(settings, 'SECRET_KEY', 'fallback-secret')
- token_part, timestamp = token.split(':')
-
- # Check if token is not too old (1 hour)
- if time.time() - int(timestamp) > 3600:
- return False
-
- user_id = str(request.user.id) if request.user.is_authenticated else 'anonymous'
- token_data = f"{user_id}:{timestamp}"
- expected_token = hmac.new(
- secret.encode(),
- token_data.encode(),
- hashlib.sha256
- ).hexdigest()
-
- return hmac.compare_digest(token_part, expected_token)
- except (ValueError, AttributeError):
- return False
-
-
-def secure_view(require_csrf=True, rate_limit=True, log_activity=True):
- """Decorator for secure view functions"""
- def decorator(view_func):
- @wraps(view_func)
- def wrapper(request, *args, **kwargs):
- # Check if user is locked out
- if SecurityManager.is_user_locked_out(request):
- SecurityManager.log_security_event(request, "Blocked request from locked out user", "blocked_request")
- return JsonResponse({
- 'status': 0,
- 'error_message': 'Account temporarily locked due to security violations. Please try again later.'
- }, status=423)
-
- # Check rate limiting
- if rate_limit and SecurityManager.is_rate_limited(request):
- SecurityManager.record_failed_attempt(request, "Rate limit exceeded")
- return JsonResponse({
- 'status': 0,
- 'error_message': 'Too many requests. Please slow down and try again later.'
- }, status=429)
-
- # CSRF protection
- if require_csrf and request.method == 'POST':
- csrf_token = request.META.get('HTTP_X_CSRFTOKEN') or request.POST.get('csrfmiddlewaretoken')
- if not csrf_token or not SecurityManager.verify_csrf_token(request, csrf_token):
- SecurityManager.record_failed_attempt(request, "Invalid CSRF token")
- return JsonResponse({
- 'status': 0,
- 'error_message': 'Invalid security token. Please refresh the page and try again.'
- }, status=403)
-
- # Log activity
- if log_activity:
- SecurityManager.log_security_event(request, f"Accessing {view_func.__name__}", "view_access")
-
- try:
- result = view_func(request, *args, **kwargs)
- # Clear failed attempts on successful request
- SecurityManager.clear_failed_attempts(request)
- return result
- except Exception as e:
- SecurityManager.log_security_event(request, f"Error in {view_func.__name__}: {str(e)}", "view_error")
- return JsonResponse({
- 'status': 0,
- 'error_message': 'An internal error occurred. Please try again later.'
- }, status=500)
-
- return wrapper
- return decorator
-
-
-def admin_required(view_func):
- """Decorator to ensure only admin users can access the view"""
- @wraps(view_func)
- def wrapper(request, *args, **kwargs):
- if not request.user.is_authenticated:
- return JsonResponse({
- 'status': 0,
- 'error_message': 'Authentication required.'
- }, status=401)
-
- if not request.user.is_staff and not request.user.is_superuser:
- SecurityManager.log_security_event(request, "Unauthorized access attempt by non-admin user", "unauthorized_access")
- return JsonResponse({
- 'status': 0,
- 'error_message': 'Admin privileges required.'
- }, status=403)
-
- return view_func(request, *args, **kwargs)
- return wrapper
diff --git a/testPlugin/signals.py b/testPlugin/signals.py
deleted file mode 100644
index 1a3d1cd6b..000000000
--- a/testPlugin/signals.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-from django.db.models.signals import post_save
-from django.dispatch import receiver
-from django.contrib.auth.models import User
-from .models import TestPluginSettings
-
-
-@receiver(post_save, sender=User)
-def create_user_settings(sender, instance, created, **kwargs):
- """Create default plugin settings when a new user is created"""
- if created:
- TestPluginSettings.objects.create(
- user=instance,
- plugin_enabled=True
- )
diff --git a/testPlugin/static/testPlugin/css/testPlugin.css b/testPlugin/static/testPlugin/css/testPlugin.css
deleted file mode 100644
index 4e978906c..000000000
--- a/testPlugin/static/testPlugin/css/testPlugin.css
+++ /dev/null
@@ -1,418 +0,0 @@
-/* Test Plugin CSS - Additional styles for better integration */
-
-/* Popup Message Animations */
-@keyframes slideInRight {
- from {
- transform: translateX(100%);
- opacity: 0;
- }
- to {
- transform: translateX(0);
- opacity: 1;
- }
-}
-
-@keyframes slideOutRight {
- from {
- transform: translateX(0);
- opacity: 1;
- }
- to {
- transform: translateX(100%);
- opacity: 0;
- }
-}
-
-/* Enhanced Button Styles */
-.btn-test {
- position: relative;
- overflow: hidden;
-}
-
-.btn-test::before {
- content: '';
- position: absolute;
- top: 50%;
- left: 50%;
- width: 0;
- height: 0;
- background: rgba(255, 255, 255, 0.3);
- border-radius: 50%;
- transform: translate(-50%, -50%);
- transition: width 0.6s, height 0.6s;
-}
-
-.btn-test:active::before {
- width: 300px;
- height: 300px;
-}
-
-/* Toggle Switch Enhanced */
-.toggle-switch {
- position: relative;
- display: inline-block;
- width: 60px;
- height: 34px;
-}
-
-.toggle-switch input {
- opacity: 0;
- width: 0;
- height: 0;
-}
-
-.slider {
- position: absolute;
- cursor: pointer;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: #ccc;
- transition: .4s;
- border-radius: 34px;
-}
-
-.slider:before {
- position: absolute;
- content: "";
- height: 26px;
- width: 26px;
- left: 4px;
- bottom: 4px;
- background-color: white;
- transition: .4s;
- border-radius: 50%;
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
-}
-
-input:checked + .slider {
- background-color: #5856d6;
-}
-
-input:checked + .slider:before {
- transform: translateX(26px);
-}
-
-/* Loading States */
-.loading {
- opacity: 0.6;
- pointer-events: none;
-}
-
-.loading::after {
- content: '';
- position: absolute;
- top: 50%;
- left: 50%;
- width: 20px;
- height: 20px;
- margin: -10px 0 0 -10px;
- border: 2px solid transparent;
- border-top: 2px solid currentColor;
- border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-/* Card Hover Effects */
-.plugin-card {
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-}
-
-.plugin-card:hover {
- transform: translateY(-8px);
- box-shadow: 0 12px 32px rgba(0,0,0,0.15);
-}
-
-/* Status Indicators */
-.status-indicator {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- padding: 6px 12px;
- border-radius: 20px;
- font-size: 12px;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.status-indicator.enabled {
- background: #e8f5e8;
- color: #388e3c;
-}
-
-.status-indicator.disabled {
- background: #ffebee;
- color: #d32f2f;
-}
-
-/* Responsive Enhancements */
-@media (max-width: 768px) {
- .control-row {
- flex-direction: column;
- align-items: stretch;
- }
-
- .control-group {
- justify-content: space-between;
- margin-bottom: 15px;
- }
-
- .stats-grid {
- grid-template-columns: 1fr;
- gap: 15px;
- }
-
- .logs-table {
- font-size: 12px;
- }
-
- .logs-table th,
- .logs-table td {
- padding: 8px 4px;
- }
-}
-
-@media (max-width: 480px) {
- .test-plugin-wrapper {
- padding: 10px;
- }
-
- .plugin-header,
- .control-panel,
- .settings-form,
- .logs-content {
- padding: 15px;
- }
-
- .plugin-header h1 {
- font-size: 24px;
- flex-direction: column;
- text-align: center;
- }
-
- .btn-test,
- .btn-secondary {
- width: 100%;
- justify-content: center;
- margin-bottom: 10px;
- }
-}
-
-/* Dark Mode Support */
-@media (prefers-color-scheme: dark) {
- :root {
- --bg-primary: #1a1a1a;
- --bg-secondary: #2d2d2d;
- --text-primary: #ffffff;
- --text-secondary: #b3b3b3;
- --text-tertiary: #808080;
- --border-primary: #404040;
- --shadow-md: 0 2px 8px rgba(0,0,0,0.3);
- --shadow-lg: 0 8px 24px rgba(0,0,0,0.4);
- }
-}
-
-/* Print Styles */
-@media print {
- .test-plugin-wrapper {
- background: white !important;
- color: black !important;
- }
-
- .btn-test,
- .btn-secondary,
- .toggle-switch {
- display: none !important;
- }
-
- .popup-message {
- display: none !important;
- }
-}
-
-/* Additional styles for inline elements */
-.popup-message {
- position: fixed;
- top: 20px;
- right: 20px;
- background: white;
- border-radius: 8px;
- padding: 16px 20px;
- box-shadow: 0 8px 24px rgba(0,0,0,0.15);
- border-left: 4px solid #10b981;
- z-index: 9999;
- max-width: 400px;
- transform: translateX(100%);
- transition: transform 0.3s ease;
-}
-
-.popup-message.show {
- transform: translateX(0);
-}
-
-.popup-message.error {
- border-left-color: #ef4444;
-}
-
-.popup-message.warning {
- border-left-color: #f59e0b;
-}
-
-.popup-title {
- font-weight: 600;
- color: var(--text-primary, #2f3640);
- margin-bottom: 4px;
-}
-
-.popup-content {
- font-size: 14px;
- color: var(--text-secondary, #64748b);
- margin-bottom: 8px;
-}
-
-.popup-time {
- font-size: 12px;
- color: var(--text-tertiary, #9ca3af);
-}
-
-.popup-close {
- position: absolute;
- top: 8px;
- right: 8px;
- background: none;
- border: none;
- font-size: 18px;
- cursor: pointer;
- color: var(--text-tertiary, #9ca3af);
-}
-
-.notification {
- position: fixed;
- top: 20px;
- right: 20px;
- background: white;
- border-radius: 8px;
- padding: 16px 20px;
- box-shadow: 0 8px 24px rgba(0,0,0,0.15);
- border-left: 4px solid #10b981;
- z-index: 9999;
- max-width: 400px;
- transform: translateX(100%);
- transition: transform 0.3s ease;
-}
-
-.notification.show {
- transform: translateX(0);
-}
-
-.notification.error {
- border-left-color: #ef4444;
-}
-
-.notification-title {
- font-weight: 600;
- color: var(--text-primary, #2f3640);
- margin-bottom: 4px;
-}
-
-.notification-content {
- font-size: 14px;
- color: var(--text-secondary, #64748b);
-}
-
-.popup-container {
- position: fixed;
- top: 0;
- right: 0;
- z-index: 9999;
- pointer-events: none;
-}
-
-/* OS Compatibility Styles */
-.compatibility-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
- gap: 20px;
- margin: 20px 0;
-}
-
-.os-card {
- background: var(--bg-secondary, #f8f9ff);
- border: 1px solid var(--border-primary, #e8e9ff);
- border-radius: 8px;
- padding: 20px;
- transition: all 0.3s ease;
-}
-
-.os-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
-}
-
-.os-card h3 {
- color: var(--text-primary, #2f3640);
- margin-bottom: 15px;
- font-size: 18px;
- font-weight: 600;
-}
-
-.os-card ul {
- list-style: none;
- padding: 0;
- margin: 0 0 15px 0;
-}
-
-.os-card li {
- padding: 5px 0;
- color: var(--text-secondary, #64748b);
- font-size: 14px;
-}
-
-.os-card p {
- margin: 5px 0;
- color: var(--text-secondary, #64748b);
- font-size: 13px;
-}
-
-.troubleshooting-section {
- margin: 20px 0;
-}
-
-.troubleshooting-section h4 {
- color: var(--text-primary, #2f3640);
- margin: 15px 0 10px 0;
- font-size: 16px;
- font-weight: 600;
-}
-
-.code-block {
- background: var(--bg-secondary, #f8f9ff);
- border: 1px solid var(--border-primary, #e8e9ff);
- border-radius: 6px;
- padding: 15px;
- margin: 10px 0;
- overflow-x: auto;
-}
-
-.code-block pre {
- margin: 0;
- font-family: 'Courier New', monospace;
- font-size: 13px;
- line-height: 1.4;
- color: var(--text-primary, #2f3640);
-}
-
-.code-block code {
- background: none;
- padding: 0;
- font-family: inherit;
- font-size: inherit;
- color: inherit;
-}
diff --git a/testPlugin/static/testPlugin/js/testPlugin.js b/testPlugin/static/testPlugin/js/testPlugin.js
deleted file mode 100644
index 988de5538..000000000
--- a/testPlugin/static/testPlugin/js/testPlugin.js
+++ /dev/null
@@ -1,323 +0,0 @@
-/**
- * Test Plugin JavaScript
- * Handles all client-side functionality for the test plugin
- */
-
-class TestPlugin {
- constructor() {
- this.init();
- }
-
- init() {
- this.bindEvents();
- this.initializeComponents();
- }
-
- bindEvents() {
- // Toggle switch functionality
- const toggleSwitch = document.getElementById('plugin-toggle');
- if (toggleSwitch) {
- toggleSwitch.addEventListener('change', (e) => this.handleToggle(e));
- }
-
- // Test button functionality
- const testButton = document.getElementById('test-button');
- if (testButton) {
- testButton.addEventListener('click', (e) => this.handleTestClick(e));
- }
-
- // Settings form
- const settingsForm = document.getElementById('settings-form');
- if (settingsForm) {
- settingsForm.addEventListener('submit', (e) => this.handleSettingsSubmit(e));
- }
-
- // Log filter
- const actionFilter = document.getElementById('action-filter');
- if (actionFilter) {
- actionFilter.addEventListener('change', (e) => this.handleLogFilter(e));
- }
- }
-
- initializeComponents() {
- // Initialize any components that need setup
- this.initializeTooltips();
- this.initializeAnimations();
- }
-
- async handleToggle(event) {
- const toggleSwitch = event.target;
- const testButton = document.getElementById('test-button');
-
- try {
- const response = await fetch('/testPlugin/toggle/', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-CSRFToken': this.getCSRFToken()
- }
- });
-
- const data = await response.json();
-
- if (data.status === 1) {
- if (testButton) {
- testButton.disabled = !data.enabled;
- }
- this.showNotification('success', 'Plugin Toggle', data.message);
-
- // Update status indicator if exists
- this.updateStatusIndicator(data.enabled);
-
- // Reload page after a short delay to update UI
- setTimeout(() => {
- window.location.reload();
- }, 1000);
- } else {
- this.showNotification('error', 'Error', data.error_message);
- // Revert toggle state
- toggleSwitch.checked = !toggleSwitch.checked;
- }
- } catch (error) {
- this.showNotification('error', 'Error', 'Failed to toggle plugin');
- // Revert toggle state
- toggleSwitch.checked = !toggleSwitch.checked;
- }
- }
-
- async handleTestClick(event) {
- const testButton = event.target;
-
- if (testButton.disabled) return;
-
- // Add loading state
- testButton.classList.add('loading');
- testButton.disabled = true;
- const originalContent = testButton.innerHTML;
- testButton.innerHTML = ' Testing...';
-
- try {
- const response = await fetch('/testPlugin/test/', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-CSRFToken': this.getCSRFToken()
- }
- });
-
- const data = await response.json();
-
- if (data.status === 1) {
- // Update test count
- const testCountElement = document.getElementById('test-count');
- if (testCountElement) {
- testCountElement.textContent = data.test_count;
- }
-
- // Show popup message
- this.showPopup(
- data.popup_message.type,
- data.popup_message.title,
- data.popup_message.message
- );
-
- // Add success animation
- testButton.style.background = 'linear-gradient(135deg, #10b981, #059669)';
- setTimeout(() => {
- testButton.style.background = '';
- }, 2000);
- } else {
- this.showNotification('error', 'Error', data.error_message);
- }
- } catch (error) {
- this.showNotification('error', 'Error', 'Failed to execute test');
- } finally {
- // Remove loading state
- testButton.classList.remove('loading');
- testButton.disabled = false;
- testButton.innerHTML = originalContent;
- }
- }
-
- async handleSettingsSubmit(event) {
- event.preventDefault();
-
- const form = event.target;
- const formData = new FormData(form);
- const data = {
- custom_message: formData.get('custom_message')
- };
-
- try {
- const response = await fetch('/testPlugin/update-settings/', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-CSRFToken': this.getCSRFToken()
- },
- body: JSON.stringify(data)
- });
-
- const result = await response.json();
-
- if (result.status === 1) {
- this.showNotification('success', 'Settings Updated', result.message);
- } else {
- this.showNotification('error', 'Error', result.error_message);
- }
- } catch (error) {
- this.showNotification('error', 'Error', 'Failed to update settings');
- }
- }
-
- handleLogFilter(event) {
- const selectedAction = event.target.value;
- const logRows = document.querySelectorAll('.log-row');
-
- logRows.forEach(row => {
- if (selectedAction === '' || row.dataset.action === selectedAction) {
- row.style.display = '';
- } else {
- row.style.display = 'none';
- }
- });
- }
-
- showPopup(type, title, message) {
- const popupContainer = document.getElementById('popup-container') || this.createPopupContainer();
- const popup = document.createElement('div');
- popup.className = `popup-message ${type}`;
-
- popup.innerHTML = `
-
-
-
-
- `;
-
- popupContainer.appendChild(popup);
-
- // Show popup with animation
- setTimeout(() => popup.classList.add('show'), 100);
-
- // Auto remove after 5 seconds
- setTimeout(() => {
- popup.classList.remove('show');
- setTimeout(() => popup.remove(), 300);
- }, 5000);
- }
-
- showNotification(type, title, message) {
- const notification = document.createElement('div');
- notification.className = `notification ${type}`;
-
- notification.innerHTML = `
- ${title}
- ${message}
- `;
-
- document.body.appendChild(notification);
-
- // Show notification
- setTimeout(() => notification.classList.add('show'), 100);
-
- // Auto remove after 3 seconds
- setTimeout(() => {
- notification.classList.remove('show');
- setTimeout(() => notification.remove(), 300);
- }, 3000);
- }
-
- createPopupContainer() {
- const container = document.createElement('div');
- container.id = 'popup-container';
- container.className = 'popup-container';
- document.body.appendChild(container);
- return container;
- }
-
- updateStatusIndicator(enabled) {
- const statusElements = document.querySelectorAll('.status-indicator');
- statusElements.forEach(element => {
- element.className = `status-indicator ${enabled ? 'enabled' : 'disabled'}`;
- element.innerHTML = enabled ?
- ' Enabled' :
- ' Disabled';
- });
- }
-
- initializeTooltips() {
- // Add tooltips to buttons and controls
- const elements = document.querySelectorAll('[data-tooltip]');
- elements.forEach(element => {
- element.addEventListener('mouseenter', (e) => this.showTooltip(e));
- element.addEventListener('mouseleave', (e) => this.hideTooltip(e));
- });
- }
-
- showTooltip(event) {
- const element = event.target;
- const tooltipText = element.dataset.tooltip;
-
- if (!tooltipText) return;
-
- const tooltip = document.createElement('div');
- tooltip.className = 'tooltip';
- tooltip.textContent = tooltipText;
- tooltip.style.cssText = `
- position: absolute;
- background: #333;
- color: white;
- padding: 8px 12px;
- border-radius: 4px;
- font-size: 12px;
- z-index: 10000;
- pointer-events: none;
- white-space: nowrap;
- `;
-
- document.body.appendChild(tooltip);
-
- const rect = element.getBoundingClientRect();
- tooltip.style.left = rect.left + (rect.width / 2) - (tooltip.offsetWidth / 2) + 'px';
- tooltip.style.top = rect.top - tooltip.offsetHeight - 8 + 'px';
-
- element._tooltip = tooltip;
- }
-
- hideTooltip(event) {
- const element = event.target;
- if (element._tooltip) {
- element._tooltip.remove();
- delete element._tooltip;
- }
- }
-
- initializeAnimations() {
- // Add entrance animations to cards
- const cards = document.querySelectorAll('.plugin-card, .stat-card, .log-item');
- cards.forEach((card, index) => {
- card.style.opacity = '0';
- card.style.transform = 'translateY(20px)';
- card.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
-
- setTimeout(() => {
- card.style.opacity = '1';
- card.style.transform = 'translateY(0)';
- }, index * 100);
- });
- }
-
- getCSRFToken() {
- const token = document.querySelector('[name=csrfmiddlewaretoken]');
- return token ? token.value : '';
- }
-}
-
-// Initialize the plugin when DOM is loaded
-document.addEventListener('DOMContentLoaded', function() {
- new TestPlugin();
-});
-
-// Export for potential external use
-window.TestPlugin = TestPlugin;
diff --git a/testPlugin/templates/testPlugin/index.html b/testPlugin/templates/testPlugin/index.html
deleted file mode 100644
index ed5250a1e..000000000
--- a/testPlugin/templates/testPlugin/index.html
+++ /dev/null
@@ -1,71 +0,0 @@
-{% extends "baseTemplate/base.html" %}
-{% load static %}
-{% load i18n %}
-
-{% block title %}
- Test Plugin - {% trans "CyberPanel" %}
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% trans "Plugin Name" %}
- {{ plugin_name }}
-
-
-
-
-
-
-
-
-
- {% trans "Version" %}
- {{ version }}
-
-
-
-
-
-
-
{% trans "Plugin Information" %}
-
{{ description }}
-
-
-
-
-
-
-
- {% trans "Test Plugin is working correctly!" %}
-
-
{% trans "This is a test plugin created for testing CyberPanel plugin functionality." %}
-
-
-
-
-
-
-
-{% endblock %}
diff --git a/testPlugin/templates/testPlugin/plugin_docs.html b/testPlugin/templates/testPlugin/plugin_docs.html
deleted file mode 100644
index 1d4d16be1..000000000
--- a/testPlugin/templates/testPlugin/plugin_docs.html
+++ /dev/null
@@ -1,1624 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Plugin Development Guide - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
-
-
-
Quick Installation Guide - CyberPanel Test Plugin
-
-
-
-
š One-Command Installation
-
Install the test plugin with a single command using curl or wget.
-
-
-
š¦ Manual Installation
-
Download and install manually with step-by-step instructions.
-
-
-
āļø Easy Management
-
Simple install/uninstall process with proper cleanup.
-
-
-
-
One-Command Installation
-
# Install the test plugin with a single command
-curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash
-
-
Manual Installation
-
- Download the plugin
- git clone https://github.com/cyberpanel/testPlugin.git
-cd testPlugin
-
- Run the installation script
- chmod +x install.sh
-./install.sh
-
- Access the plugin
-
- URL: https://your-domain:8090/testPlugin/
- Login with your CyberPanel admin credentials
-
-
-
-
-
Features Included
-
-
-
ā
Enable/Disable Toggle
-
Toggle the plugin on/off with a beautiful switch
-
-
-
ā
Test Button
-
Click to show popup messages from the side
-
-
-
ā
Settings Page
-
Configure custom messages and preferences
-
-
-
ā
Activity Logs
-
View all plugin activities with filtering
-
-
-
ā
Inline Integration
-
Loads within CyberPanel interface
-
-
-
ā
Responsive Design
-
Works perfectly on all devices
-
-
-
-
Uninstallation
-
# Uninstall the plugin
-./install.sh --uninstall
-
-
Troubleshooting
-
If you encounter any issues:
-
- Check CyberPanel logs
- tail -f /home/cyberpanel/logs/cyberpanel.log
-
- Restart CyberPanel services
- systemctl restart lscpd
-systemctl restart cyberpanel
-
- Verify installation
- ls -la /home/cyberpanel/plugins/testPlugin
-ls -la /usr/local/CyberCP/testPlugin
-
-
-
-
- Note: This plugin is designed for testing and development purposes. Always backup your system before installing any plugins.
-
-
-
-
-
-
-
-
Getting Started with CyberPanel Plugin Development
-
-
-
-
šÆ Official Documentation
-
Based on the official CyberPanel plugin development guide from the CyberPanel team.
-
-
-
š Step-by-Step Tutorial
-
Complete walkthrough from development environment setup to plugin installation.
-
-
-
š§ Signal Integration
-
Learn how to hook into CyberPanel events and respond to core functionality.
-
-
-
-
- Source: This guide is based on the official CyberPanel documentation and the beautiful_names plugin repository .
-
-
-
Prerequisites
-
- Python - Clear understanding of Python Programming Language
- Django - Experience with Django framework
- HTML (Basic) - Basic HTML knowledge
- CSS (Basic) - Basic CSS knowledge
-
-
-
Note: You can use plain JavaScript in your plugins or any JavaScript framework. You just have to follow the norms of Django framework, because CyberPanel plugin is just another Django app.
-
-
Step 1: Set up your Development Environment
-
-
Clone CyberPanel Repository
-
git clone https://github.com/usmannasir/cyberpanel/ --single-branch v1.7.2-plugin
-
-
Create a Django App
-
cd v1.7.2-plugin
-django-admin startapp pluginName
-
-
Choose your plugin name wisely as it's of great importance. Once the Django app is created, you need to define a meta file for your plugin so that CyberPanel can read information about your plugin.
-
-
Create Meta File
-
cd pluginName
-nano meta.xml
-
-
Paste the following content in the meta.xml file:
-
<?xml version="1.0" encoding="UTF-8"?>
-<cyberpanelPluginConfig>
- <name>customplugin</name>
- <type>plugin</type>
- <description>Plugin to make custom changes</description>
- <version>0</version>
-</cyberpanelPluginConfig>
-
-
Step 2: Creating a Signal File and Adjusting Settings
-
-
Create Signals File
-
Create a signals.py file (you can name it anything, but signals.py is recommended). You can leave this file empty for now.
-
-
Configure apps.py
-
In your apps.py file, you need to import the signals file inside the ready function:
-
def ready(self):
- import signals
-
-
Configure __init__.py
-
You need to specify a default_app_config variable in this file:
-
default_app_config = 'examplePlugin.apps.ExamplepluginConfig'
-
-
Create urls.py
-
Inside your app root directory, create urls.py and paste this content:
-
from django.conf.urls import url
-import views
-
-urlpatterns = [
- url(r'^$', views.examplePlugin, name='examplePlugin'),
-]
-
-
Important: Replace examplePlugin with your plugin name. This URL definition is very important for CyberPanel to register your plugin page.
-
-
Optional Files
-
You can create these optional files for database model management:
-
- pre_install - Executed before installation of plugin
- post_install - Executed after installation of plugin
-
-
-
If your file is Python code, don't forget to include this line at the top:
-
#!/usr/local/CyberCP/bin/python2
-
-
Step 3: Responding to Events
-
-
To plug into events fired by CyberPanel core, you can respond to various events happening in the core. Visit the signal file documentation for a complete list of events.
-
-
Example Events
-
- preWebsiteCreation - Fired before CyberPanel starts the creation of website
- postWebsiteDeletion - Fired after core finished the deletion of website
-
-
-
Responding to Events
-
Here's how you can respond to the postWebsiteDeletion event:
-
from django.dispatch import receiver
-from django.http import HttpResponse
-from websiteFunctions.signals import postWebsiteDeletion
-from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
-
-@receiver(postWebsiteDeletion)
-def rcvr(sender, **kwargs):
- request = kwargs['request']
- logging.writeToFile('Hello World from Example Plugin.')
- return HttpResponse('Hello World from Example Plugin.')
-
-
Return Values
-
- HttpResponse object - CyberPanel core will stop further processing and return your response to browser
- int 200 - CyberPanel core will continue processing, assuming the event was successfully executed
-
-
-
Step 4: Packing, Shipping and Installing Plugin
-
-
Package Your Plugin
-
After completing your plugin, zip your Django app. The zip file name should be your plugin name (e.g., examplePlugin.zip), otherwise installation will fail.
-
-
Installation
-
First, upload your plugin to /usr/local/CyberCP/pluginInstaller:
-
cd /usr/local/CyberCP/pluginInstaller
-python pluginInstaller.py install --pluginName examplePlugin
-
-
Uninstall
-
cd /usr/local/CyberCP/pluginInstaller
-python pluginInstaller.py remove --pluginName examplePlugin
-
-
Beautiful Names Plugin Example
-
CyberPanel has released an official plugin called Beautiful Names that removes the admin_ prefix from Package and FTP account names. This plugin serves as a great example of how to create CyberPanel plugins.
-
-
Installation of Beautiful Names
-
cd /usr/local/CyberCP/pluginInstaller
-wget https://cyberpanel.net/beautifulNames.zip
-python pluginInstaller.py install --pluginName beautifulNames
-
-
Uninstall Beautiful Names
-
cd /usr/local/CyberCP/pluginInstaller
-python pluginInstaller.py remove --pluginName beautifulNames
-
-
Plugin Installation Facility
-
The plugin installation facility is in beta and not available with the official install yet. To install plugins, you need to install CyberPanel via the test version:
-
sh <(curl https://mirror.cyberpanel.net/install-test.sh || wget -O - https://mirror.cyberpanel.net/install-test.sh)
-
-
Additional Resources
-
-
-
- Note: This guide is based on the official CyberPanel documentation. For the most up-to-date information, always refer to the official sources.
-
-
-
-
-
-
-
-
CyberPanel Plugin Development Guide
-
-
-
-
-
How to Install Plugins
-
-
Method 1: Using the Installation Script (Recommended)
-
# Download and run the installation script
-curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash
-
-# Or download first, then run
-wget https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh
-chmod +x install.sh
-./install.sh
-
-
Method 2: Manual Installation
-
- Create Plugin Directory Structure
- mkdir -p /home/cyberpanel/plugins/yourPlugin
-mkdir -p /usr/local/CyberCP/yourPlugin
-
- Copy Plugin Files
- cp -r yourPlugin/* /usr/local/CyberCP/yourPlugin/
-chown -R cyberpanel:cyberpanel /usr/local/CyberCP/yourPlugin
-chmod -R 755 /usr/local/CyberCP/yourPlugin
-
- Create Symlink
- ln -sf /usr/local/CyberCP/yourPlugin /home/cyberpanel/plugins/yourPlugin
-
- Update Django Settings
- Add your plugin to INSTALLED_APPS in /usr/local/CyberCP/cyberpanel/settings.py:
- INSTALLED_APPS = [
- # ... existing apps ...
- 'yourPlugin',
-]
-
- Update URL Configuration
- Add your plugin URLs in /usr/local/CyberCP/cyberpanel/urls.py:
- urlpatterns = [
- # ... existing patterns ...
- path("yourPlugin/", include("yourPlugin.urls")),
-]
-
- Run Migrations
- cd /usr/local/CyberCP
-python3 manage.py makemigrations yourPlugin
-python3 manage.py migrate yourPlugin
-
- Collect Static Files
- python3 manage.py collectstatic --noinput
-
- Restart Services
- systemctl restart lscpd
-systemctl restart cyberpanel
-
-
-
-
-
-
How to Uninstall Plugins
-
-
Method 1: Using the Installation Script
-
# Run with uninstall flag
-./install.sh --uninstall
-
-
Method 2: Manual Uninstallation
-
- Remove Plugin Files
- rm -rf /usr/local/CyberCP/yourPlugin
-rm -f /home/cyberpanel/plugins/yourPlugin
-
- Remove from Django Settings
- sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/settings.py
-
- Remove from URLs
- sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/urls.py
-
- Restart Services
- systemctl restart lscpd
-systemctl restart cyberpanel
-
-
-
-
-
-
-
-
-
-
How to Add Toggles
-
-
1. HTML Structure
-
<div class="control-group">
- <label for="plugin-toggle" class="toggle-label">
- Enable Feature
- </label>
- <label class="toggle-switch">
- <input type="checkbox" id="plugin-toggle" {% if feature_enabled %}checked{% endif %}>
- <span class="slider"></span>
- </label>
-</div>
-
-
2. CSS Styles
-
.toggle-switch {
- position: relative;
- display: inline-block;
- width: 60px;
- height: 34px;
-}
-
-.toggle-switch input {
- opacity: 0;
- width: 0;
- height: 0;
-}
-
-.slider {
- position: absolute;
- cursor: pointer;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: #ccc;
- transition: .4s;
- border-radius: 34px;
-}
-
-.slider:before {
- position: absolute;
- content: "";
- height: 26px;
- width: 26px;
- left: 4px;
- bottom: 4px;
- background-color: white;
- transition: .4s;
- border-radius: 50%;
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
-}
-
-input:checked + .slider {
- background-color: #5856d6;
-}
-
-input:checked + .slider:before {
- transform: translateX(26px);
-}
-
-
3. JavaScript Handling
-
document.getElementById('plugin-toggle').addEventListener('change', function() {
- fetch('/yourPlugin/toggle/', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-CSRFToken': getCSRFToken()
- }
- })
- .then(response => response.json())
- .then(data => {
- if (data.status === 1) {
- showNotification('success', 'Toggle Updated', data.message);
- } else {
- showNotification('error', 'Error', data.error_message);
- // Revert toggle state
- this.checked = !this.checked;
- }
- });
-});
-
-
-
-
-
-
-
-
-
-
How to Make Plugins Load Inline
-
-
1. Use CyberPanel's httpProc
-
# views.py
-from plogical.httpProc import httpProc
-
-def your_view(request):
- context = {
- 'data': 'your_data',
- 'plugin_enabled': True
- }
-
- proc = httpProc(request, 'yourPlugin/your_template.html', context, 'admin')
- return proc.render()
-
-
2. Template Structure
-
{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-<style>
- /* Your plugin-specific styles */
- .your-plugin-wrapper {
- background: transparent;
- padding: 20px;
- }
-
- .your-plugin-container {
- max-width: 1200px;
- margin: 0 auto;
- }
-</style>
-{% endblock %}
-
-{% block content %}
-<div class="your-plugin-wrapper">
- <div class="your-plugin-container">
- <!-- Your plugin content here -->
- </div>
-</div>
-{% endblock %}
-
-
3. URL Configuration
-
# urls.py
-from django.urls import path
-from . import views
-
-app_name = 'yourPlugin'
-
-urlpatterns = [
- path('', views.your_view, name='your_view'),
- path('settings/', views.settings_view, name='settings'),
- # ... other URLs
-]
-
-
4. Main URLs Integration
-
# In /usr/local/CyberCP/cyberpanel/urls.py
-urlpatterns = [
- # ... existing patterns ...
- path("yourPlugin/", include("yourPlugin.urls")),
-]
-
-
-
-
Plugin Structure Overview
-
yourPlugin/
-āāā __init__.py
-āāā admin.py
-āāā apps.py
-āāā models.py
-āāā views.py
-āāā urls.py
-āāā signals.py
-āāā meta.xml
-āāā install.sh
-āāā templates/
-ā āāā yourPlugin/
-ā āāā plugin_home.html
-ā āāā plugin_settings.html
-ā āāā plugin_logs.html
-āāā static/
-ā āāā yourPlugin/
-ā āāā css/
-ā ā āāā yourPlugin.css
-ā āāā js/
-ā āāā yourPlugin.js
-āāā migrations/
- āāā __init__.py
-
-
-
-
Best Practices
-
-
1. Security
-
- Always validate user input
- Use CSRF protection
- Sanitize data before displaying
- Use proper authentication decorators
-
-
-
2. Performance
-
- Use database indexes for frequently queried fields
- Implement caching where appropriate
- Optimize database queries
- Minimize JavaScript and CSS
-
-
-
3. User Experience
-
- Provide clear feedback for all actions
- Use loading states for long operations
- Implement proper error handling
- Make the interface responsive
-
-
-
4. Code Quality
-
- Follow Django best practices
- Use meaningful variable names
- Add proper documentation
- Write unit tests
-
-
-
5. Integration
-
- Use CyberPanel's existing components
- Follow the established design patterns
- Maintain consistency with the UI
- Test thoroughly before release
-
-
-
-
-
Troubleshooting
-
-
Common Issues
-
-
1. Plugin not showing in installed plugins
-
- Check if meta.xml exists and is valid
- Verify the plugin is in INSTALLED_APPS
- Ensure proper file permissions
-
-
-
2. Template not found errors
-
- Check template path in views.py
- Verify template files exist
- Ensure proper directory structure
-
-
-
3. Static files not loading
-
- Run python3 manage.py collectstatic
- Check STATIC_URL configuration
- Verify file permissions
-
-
-
4. Database migration errors
-
- Check model definitions
- Run python3 manage.py makemigrations
- Verify database connectivity
-
-
-
5. Permission denied errors
-
- Check file ownership (cyberpanel:cyberpanel)
- Verify file permissions (755 for directories, 644 for files)
- Ensure proper SELinux context if applicable
-
-
-
Debug Steps
-
-
1. Check CyberPanel logs
-
tail -f /home/cyberpanel/logs/cyberpanel.log
-
-
2. Check Django logs
-
tail -f /home/cyberpanel/logs/django.log
-
-
3. Verify plugin installation
-
ls -la /home/cyberpanel/plugins/
-ls -la /usr/local/CyberCP/yourPlugin/
-
-
4. Test database connectivity
-
cd /usr/local/CyberCP
-python3 manage.py shell
-
-
5. Check service status
-
systemctl status lscpd
-systemctl status cyberpanel
-
-
-
- Conclusion: This guide provides comprehensive instructions for developing CyberPanel plugins. Follow the best practices and troubleshooting steps to ensure your plugins integrate seamlessly with CyberPanel while maintaining security and performance standards.
-
-
-
-
-
-
-
-
-
-
Operating System Compatibility
-
-
-
-
š Multi-OS Support
-
Comprehensive support for all CyberPanel-supported operating systems.
-
-
-
š Automatic Detection
-
Intelligent OS detection and configuration for seamless installation.
-
-
-
š§Ŗ Compatibility Testing
-
Built-in compatibility testing to verify system requirements.
-
-
-
-
Supported Operating Systems
-
-
-
-
Ubuntu
-
- ā
Ubuntu 22.04 (Full Support)
- ā
Ubuntu 20.04 (Full Support)
- ā
Debian 11+ (Compatible)
-
-
Package Manager: apt-get
-
Web Server: apache2
-
-
-
-
RHEL-based
-
- ā
AlmaLinux 8, 9, 10
- ā
RockyLinux 8, 9
- ā
RHEL 8, 9
- ā
CentOS 9
-
-
Package Manager: dnf/yum
-
Web Server: httpd
-
-
-
-
CloudLinux
-
- ā
CloudLinux 8
- ā
CloudLinux 7 (Limited)
-
-
Package Manager: yum
-
Web Server: httpd
-
-
-
-
Python Compatibility
-
The plugin requires Python 3.6+ and automatically detects the correct Python executable:
-
-
-
# Detection order:
-1. python3.12
-2. python3.11
-3. python3.10
-4. python3.9
-5. python3.8
-6. python3.7
-7. python3.6
-8. python3
-9. python (fallback)
-
-
-
Installation Compatibility
-
The installation script automatically detects your operating system and configures the plugin accordingly:
-
-
-
# Automatic detection includes:
-- OS name and version
-- Python executable path
-- Package manager (apt-get, dnf, yum)
-- Service manager (systemctl, service)
-- Web server (apache2, httpd)
-- User and group permissions
-
-
-
Compatibility Testing
-
Run the built-in compatibility test to verify your system:
-
-
-
# Navigate to plugin directory
-cd /usr/local/CyberCP/testPlugin
-
-# Run compatibility test
-python3 test_os_compatibility.py
-
-# Or make it executable and run
-chmod +x test_os_compatibility.py
-./test_os_compatibility.py
-
-
-
Test Results
-
The compatibility test checks:
-
- ā
OS detection and version
- ā
Python installation and version
- ā
Package manager availability
- ā
Service manager functionality
- ā
Web server configuration
- ā
File permissions and ownership
- ā
Network connectivity
- ā
CyberPanel integration
-
-
-
OS-Specific Configurations
-
-
Ubuntu/Debian Systems
-
-
# Package Manager: apt-get
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: apache2
-# User/Group: cyberpanel:cyberpanel
-
-# Installation commands
-sudo apt-get update
-sudo apt-get install -y python3 python3-pip python3-venv git curl
-sudo apt-get install -y build-essential python3-dev
-
-
-
RHEL-based Systems
-
-
# Package Manager: dnf (RHEL 8+) / yum (RHEL 7)
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: httpd
-# User/Group: cyberpanel:cyberpanel
-
-# Installation commands (RHEL 8+)
-sudo dnf install -y python3 python3-pip python3-devel git curl
-sudo dnf install -y gcc gcc-c++ make
-
-# Installation commands (RHEL 7)
-sudo yum install -y python3 python3-pip python3-devel git curl
-sudo yum install -y gcc gcc-c++ make
-
-
-
CloudLinux
-
-
# Package Manager: yum
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: httpd
-# User/Group: cyberpanel:cyberpanel
-
-# Installation commands
-sudo yum install -y python3 python3-pip python3-devel git curl
-sudo yum install -y gcc gcc-c++ make
-
-# CageFS configuration
-cagefsctl --enable cyberpanel
-cagefsctl --update
-
-
-
Security Compatibility
-
-
SELinux (RHEL-based systems)
-
-
# Check SELinux status
-sestatus
-
-# Set proper context for plugin files
-setsebool -P httpd_can_network_connect 1
-chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/
-
-
-
AppArmor (Ubuntu/Debian)
-
-
# Check AppArmor status
-aa-status
-
-# Allow Apache to access plugin files
-aa-complain apache2
-
-
-
Firewall Configuration
-
-
# Ubuntu/Debian (ufw)
-sudo ufw allow 8090/tcp
-sudo ufw allow 80/tcp
-sudo ufw allow 443/tcp
-
-# RHEL-based (firewalld)
-sudo firewall-cmd --permanent --add-port=8090/tcp
-sudo firewall-cmd --permanent --add-port=80/tcp
-sudo firewall-cmd --permanent --add-port=443/tcp
-sudo firewall-cmd --reload
-
-
-
Troubleshooting
-
-
Common Issues
-
-
Python not found
-
-
# Ubuntu/Debian
-sudo apt-get update
-sudo apt-get install -y python3 python3-pip
-
-# RHEL-based
-sudo dnf install -y python3 python3-pip
-# or
-sudo yum install -y python3 python3-pip
-
-
-
Permission denied
-
-
sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
-sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin
-
-
-
Service not starting
-
-
sudo systemctl daemon-reload
-sudo systemctl restart lscpd
-sudo systemctl restart apache2 # Ubuntu/Debian
-sudo systemctl restart httpd # RHEL-based
-
-
-
-
Debug Commands
-
-
# Check OS information
-cat /etc/os-release
-uname -a
-
-# Check Python installation
-python3 --version
-which python3
-which pip3
-
-# Check services
-systemctl status lscpd
-systemctl status apache2 # Ubuntu/Debian
-systemctl status httpd # RHEL-based
-
-# Check file permissions
-ls -la /home/cyberpanel/plugins/
-ls -la /usr/local/CyberCP/testPlugin/
-
-# Check CyberPanel logs
-tail -f /home/cyberpanel/logs/cyberpanel.log
-tail -f /home/cyberpanel/logs/django.log
-
-
-
- Note: The plugin is designed to work seamlessly across all supported operating systems. If you encounter any compatibility issues, please run the compatibility test and check the troubleshooting section above.
-
-
-
-
-
-{% endblock %}
diff --git a/testPlugin/templates/testPlugin/plugin_home.html b/testPlugin/templates/testPlugin/plugin_home.html
deleted file mode 100644
index 3ef326229..000000000
--- a/testPlugin/templates/testPlugin/plugin_home.html
+++ /dev/null
@@ -1,571 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Test Plugin - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
-
- {% trans "Enable Plugin" %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ settings.test_count|default:0 }}
-
{% trans "Test Clicks" %}
-
-
-
-
- {% if plugin_enabled %}
-
- {% else %}
-
- {% endif %}
-
-
{% trans "Plugin Status" %}
-
-
-
-
{{ recent_logs|length }}
-
{% trans "Recent Activities" %}
-
-
-
-
-
-
-
- {% trans "Recent Activity" %}
-
-
-
- {% for log in recent_logs %}
-
-
- {% if 'click' in log.action %}
-
- {% elif 'toggle' in log.action %}
-
- {% elif 'settings' in log.action %}
-
- {% else %}
-
- {% endif %}
-
-
-
{{ log.action|title }}
-
{{ log.message }}
-
-
{{ log.timestamp|date:"M d, H:i" }}
-
- {% empty %}
-
-
-
{% trans "No recent activity" %}
-
- {% endfor %}
-
-
-
-
-
-
-
-
-
-{% endblock %}
diff --git a/testPlugin/templates/testPlugin/plugin_logs.html b/testPlugin/templates/testPlugin/plugin_logs.html
deleted file mode 100644
index 88771663a..000000000
--- a/testPlugin/templates/testPlugin/plugin_logs.html
+++ /dev/null
@@ -1,291 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Test Plugin Logs - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
- {% if logs %}
-
-
-
- {% trans "Action" %}
- {% trans "Message" %}
- {% trans "Timestamp" %}
-
-
-
- {% for log in logs %}
-
-
-
- {% if 'click' in log.action %}
-
- {% elif 'toggle' in log.action %}
-
- {% elif 'settings' in log.action %}
-
- {% elif 'visit' in log.action %}
-
- {% else %}
-
- {% endif %}
-
- {{ log.action|title|replace:"_":" " }}
-
- {{ log.message }}
- {{ log.timestamp|date:"M d, Y H:i:s" }}
-
- {% endfor %}
-
-
- {% else %}
-
-
-
{% trans "No Logs Found" %}
-
{% trans "No activity logs available yet. Start using the plugin to see logs here." %}
-
- {% endif %}
-
-
-
-
-
-{% endblock %}
diff --git a/testPlugin/templates/testPlugin/plugin_settings.html b/testPlugin/templates/testPlugin/plugin_settings.html
deleted file mode 100644
index 6368cb739..000000000
--- a/testPlugin/templates/testPlugin/plugin_settings.html
+++ /dev/null
@@ -1,264 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Test Plugin Settings - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-{% endblock %}
diff --git a/testPlugin/templates/testPlugin/security_info.html b/testPlugin/templates/testPlugin/security_info.html
deleted file mode 100644
index 66c765c66..000000000
--- a/testPlugin/templates/testPlugin/security_info.html
+++ /dev/null
@@ -1,499 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Security Information - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
15+
-
{% trans "Security Features" %}
-
-
-
99%
-
{% trans "Attack Prevention" %}
-
-
-
24/7
-
{% trans "Monitoring" %}
-
-
-
0
-
{% trans "Known Vulnerabilities" %}
-
-
-
-
-
-
-
- {% trans "Back to Plugin" %}
-
-
-
{% trans "Security Features Implemented" %}
-
-
-
-
-
-
- {% trans "Authentication & Authorization" %}
-
-
{% trans "Multi-layered authentication and authorization system" %}
-
-
-
- {% trans "Admin-only access required for all plugin functions" %}
-
-
-
- {% trans "User session validation on every request" %}
-
-
-
- {% trans "Privilege escalation protection" %}
-
-
-
-
-
-
-
-
-
- {% trans "Rate Limiting & Brute Force Protection" %}
-
-
{% trans "Advanced rate limiting to prevent brute force attacks" %}
-
-
-
- {% trans "50 requests per 5-minute window per user" %}
-
-
-
- {% trans "10 test button clicks per minute limit" %}
-
-
-
- {% trans "Automatic lockout after 5 failed attempts" %}
-
-
-
- {% trans "15-minute lockout duration" %}
-
-
-
-
-
-
-
-
-
- {% trans "CSRF Protection" %}
-
-
{% trans "Cross-Site Request Forgery protection on all POST requests" %}
-
-
-
- {% trans "HMAC-based CSRF token validation" %}
-
-
-
- {% trans "Token expiration after 1 hour" %}
-
-
-
- {% trans "User-specific token generation" %}
-
-
-
-
-
-
-
-
-
- {% trans "Input Validation & Sanitization" %}
-
-
{% trans "Comprehensive input validation and sanitization" %}
-
-
-
- {% trans "Regex-based input validation" %}
-
-
-
- {% trans "XSS attack prevention" %}
-
-
-
- {% trans "SQL injection prevention" %}
-
-
-
- {% trans "Path traversal protection" %}
-
-
-
- {% trans "Maximum input length limits" %}
-
-
-
-
-
-
-
-
-
- {% trans "Security Monitoring & Logging" %}
-
-
{% trans "Comprehensive security event monitoring and logging" %}
-
-
-
- {% trans "All security events logged with IP and user agent" %}
-
-
-
- {% trans "Failed attempt tracking and alerting" %}
-
-
-
- {% trans "Suspicious activity detection" %}
-
-
-
- {% trans "Real-time security event monitoring" %}
-
-
-
-
-
-
-
-
-
- {% trans "HTTP Security Headers" %}
-
-
{% trans "Comprehensive HTTP security headers for additional protection" %}
-
-
-
- {% trans "X-Frame-Options: DENY (clickjacking protection)" %}
-
-
-
- {% trans "X-Content-Type-Options: nosniff" %}
-
-
-
- {% trans "X-XSS-Protection: 1; mode=block" %}
-
-
-
- {% trans "Content-Security-Policy (CSP)" %}
-
-
-
- {% trans "Strict-Transport-Security (HSTS)" %}
-
-
-
- {% trans "Referrer-Policy: strict-origin-when-cross-origin" %}
-
-
-
-
-
-
-
-
-
- {% trans "Data Isolation & Privacy" %}
-
-
{% trans "User data isolation and privacy protection" %}
-
-
-
- {% trans "User-specific data isolation" %}
-
-
-
- {% trans "Logs restricted to user's own activities" %}
-
-
-
- {% trans "Settings isolated per user" %}
-
-
-
- {% trans "No cross-user data access" %}
-
-
-
-
-
-
-
-
-
- {% trans "Security Recommendations" %}
-
-
{% trans "Additional security measures you should implement" %}
-
-
-
- {% trans "Keep CyberPanel and all plugins updated" %}
-
-
-
- {% trans "Use strong, unique passwords" %}
-
-
-
- {% trans "Enable 2FA on your CyberPanel account" %}
-
-
-
- {% trans "Regularly review security logs" %}
-
-
-
- {% trans "Use HTTPS in production environments" %}
-
-
-
-
-
-
-
-
-
- {% trans "Security Vulnerability Reporting" %}
-
-
{% trans "If you discover a security vulnerability, please report it responsibly" %}
-
-
-
- {% trans "Email: security@cyberpanel.net" %}
-
-
-
- {% trans "GitHub: Create a private security issue" %}
-
-
-
- {% trans "Response time: Within 24-48 hours" %}
-
-
-
-
-
{% trans "Security Audit Results" %}
-
{% trans "This plugin has been designed with security as a top priority. All major security vulnerabilities have been addressed:" %}
-
-
-
-
- {% trans "OWASP Top 10 vulnerabilities addressed" %}
-
-
-
- {% trans "No SQL injection vulnerabilities" %}
-
-
-
- {% trans "No XSS vulnerabilities" %}
-
-
-
- {% trans "No CSRF vulnerabilities" %}
-
-
-
- {% trans "No authentication bypass vulnerabilities" %}
-
-
-
- {% trans "No authorization bypass vulnerabilities" %}
-
-
-
- {% trans "No information disclosure vulnerabilities" %}
-
-
-
- {% trans "No path traversal vulnerabilities" %}
-
-
-
-
- {% trans "Security Note:" %} {% trans "This plugin implements enterprise-grade security measures. However, security is an ongoing process. Regular updates and monitoring are essential to maintain the highest security standards." %}
-
-
-
-
-{% endblock %}
diff --git a/testPlugin/templates/testPlugin/settings.html b/testPlugin/templates/testPlugin/settings.html
deleted file mode 100644
index e06f901f4..000000000
--- a/testPlugin/templates/testPlugin/settings.html
+++ /dev/null
@@ -1,165 +0,0 @@
-{% extends "baseTemplate/index.html" %}
-{% load static %}
-{% load i18n %}
-
-{% block title %}
- Test Plugin Settings - {% trans "CyberPanel" %}
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
{% trans "Plugin Information" %}
-
- {% trans "Name" %}: {{ plugin_name }}
- {% trans "Version" %}: {{ version }}
- {% trans "Status" %}: {% trans "Active" %}
-
-
-
-
-
-
-
- {% csrf_token %}
-
-
-
-
-
-
- {% trans "Test Text Input" %}
-
-
-
- {% trans "This is a test text input field." %}
-
-
-
-
-
-
- {% trans "Test Select Option" %}
-
-
- {% trans "Option 1" %}
- {% trans "Option 2" %}
- {% trans "Option 3" %}
-
-
- {% trans "Select a test option from the dropdown." %}
-
-
-
-
-
-
- {% trans "Save Settings" %}
-
-
-
- {% trans "Reset" %}
-
-
-
-
-
-
-
-
-
-
-
-
{% trans "Plugin is Active" %}
-
{% trans "The Test Plugin is installed and working correctly." %}
-
-
-
-
-
-
-
-
-
- {% trans "Plugin Name" %}
- {{ plugin_name }}
-
-
-
-
-
-
-
-
-
- {% trans "Version" %}
- {{ version }}
-
-
-
-
-
-
-
-
-
-
-
{{ description }}
-
{% trans "This is a test plugin created for testing CyberPanel plugin functionality. You can use this plugin to verify that the plugin system is working correctly." %}
-
-
{% trans "Features" %}
-
- {% trans "Enable/disable functionality" %}
- {% trans "Test button" %}
- {% trans "Popup messages" %}
- {% trans "Inline integration" %}
- {% trans "Settings page" %}
-
-
-
-
-
-
-
-
-{% endblock %}
diff --git a/testPlugin/test_os_compatibility.py b/testPlugin/test_os_compatibility.py
deleted file mode 100644
index 46c6d5dc6..000000000
--- a/testPlugin/test_os_compatibility.py
+++ /dev/null
@@ -1,446 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-OS Compatibility Test Script for Test Plugin
-Tests the plugin on different operating systems
-"""
-import os
-import sys
-import subprocess
-import platform
-import json
-from pathlib import Path
-
-# Add the plugin directory to Python path
-plugin_dir = Path(__file__).parent
-sys.path.insert(0, str(plugin_dir))
-
-from os_config import OSConfig
-
-
-class OSCompatibilityTester:
- """Test OS compatibility for the Test Plugin"""
-
- def __init__(self):
- self.os_config = OSConfig()
- self.test_results = {}
-
- def run_all_tests(self):
- """Run all compatibility tests"""
- print("š Testing OS Compatibility for CyberPanel Test Plugin")
- print("=" * 60)
-
- # Test 1: OS Detection
- self.test_os_detection()
-
- # Test 2: Python Detection
- self.test_python_detection()
-
- # Test 3: Package Manager Detection
- self.test_package_manager_detection()
-
- # Test 4: Service Manager Detection
- self.test_service_manager_detection()
-
- # Test 5: Web Server Detection
- self.test_web_server_detection()
-
- # Test 6: File Permissions
- self.test_file_permissions()
-
- # Test 7: Network Connectivity
- self.test_network_connectivity()
-
- # Test 8: CyberPanel Integration
- self.test_cyberpanel_integration()
-
- # Display results
- self.display_results()
-
- return self.test_results
-
- def test_os_detection(self):
- """Test OS detection functionality"""
- print("\nš Testing OS Detection...")
-
- try:
- os_info = self.os_config.get_os_info()
- is_supported = self.os_config.is_supported_os()
-
- self.test_results['os_detection'] = {
- 'status': 'PASS',
- 'os_name': os_info['name'],
- 'os_version': os_info['version'],
- 'os_arch': os_info['architecture'],
- 'is_supported': is_supported,
- 'platform': os_info['platform']
- }
-
- print(f" ā
OS: {os_info['name']} {os_info['version']} ({os_info['architecture']})")
- print(f" ā
Supported: {is_supported}")
-
- except Exception as e:
- self.test_results['os_detection'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_python_detection(self):
- """Test Python detection and version"""
- print("\nš Testing Python Detection...")
-
- try:
- python_path = self.os_config.python_path
- pip_path = self.os_config.pip_path
-
- # Test Python version
- result = subprocess.run([python_path, '--version'],
- capture_output=True, text=True, timeout=10)
-
- if result.returncode == 0:
- version = result.stdout.strip()
- version_num = version.split()[1]
- major, minor = map(int, version_num.split('.')[:2])
-
- is_compatible = major == 3 and minor >= 6
-
- self.test_results['python_detection'] = {
- 'status': 'PASS' if is_compatible else 'WARN',
- 'python_path': python_path,
- 'pip_path': pip_path,
- 'version': version,
- 'is_compatible': is_compatible
- }
-
- print(f" ā
Python: {version}")
- print(f" ā
Path: {python_path}")
- print(f" ā
Pip: {pip_path}")
- print(f" {'ā
' if is_compatible else 'ā ļø'} Compatible: {is_compatible}")
-
- else:
- raise Exception("Python not working properly")
-
- except Exception as e:
- self.test_results['python_detection'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_package_manager_detection(self):
- """Test package manager detection"""
- print("\nš¦ Testing Package Manager Detection...")
-
- try:
- package_manager = self.os_config.package_manager
- config = self.os_config.get_os_specific_config()
-
- # Test if package manager is available
- if package_manager in ['apt-get', 'apt']:
- test_cmd = ['apt', '--version']
- elif package_manager == 'dnf':
- test_cmd = ['dnf', '--version']
- elif package_manager == 'yum':
- test_cmd = ['yum', '--version']
- else:
- test_cmd = None
-
- is_available = True
- if test_cmd:
- try:
- result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=5)
- is_available = result.returncode == 0
- except:
- is_available = False
-
- self.test_results['package_manager'] = {
- 'status': 'PASS' if is_available else 'WARN',
- 'package_manager': package_manager,
- 'is_available': is_available,
- 'config': config
- }
-
- print(f" ā
Package Manager: {package_manager}")
- print(f" {'ā
' if is_available else 'ā ļø'} Available: {is_available}")
-
- except Exception as e:
- self.test_results['package_manager'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_service_manager_detection(self):
- """Test service manager detection"""
- print("\nš§ Testing Service Manager Detection...")
-
- try:
- service_manager = self.os_config.service_manager
- web_server = self.os_config.web_server
-
- # Test if service manager is available
- if service_manager == 'systemctl':
- test_cmd = ['systemctl', '--version']
- elif service_manager == 'service':
- test_cmd = ['service', '--version']
- else:
- test_cmd = None
-
- is_available = True
- if test_cmd:
- try:
- result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=5)
- is_available = result.returncode == 0
- except:
- is_available = False
-
- self.test_results['service_manager'] = {
- 'status': 'PASS' if is_available else 'WARN',
- 'service_manager': service_manager,
- 'web_server': web_server,
- 'is_available': is_available
- }
-
- print(f" ā
Service Manager: {service_manager}")
- print(f" ā
Web Server: {web_server}")
- print(f" {'ā
' if is_available else 'ā ļø'} Available: {is_available}")
-
- except Exception as e:
- self.test_results['service_manager'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_web_server_detection(self):
- """Test web server detection"""
- print("\nš Testing Web Server Detection...")
-
- try:
- web_server = self.os_config.web_server
-
- # Check if web server is installed
- if web_server == 'apache2':
- config_paths = ['/etc/apache2/apache2.conf', '/etc/apache2/httpd.conf']
- else: # httpd
- config_paths = ['/etc/httpd/conf/httpd.conf', '/etc/httpd/conf.d']
-
- is_installed = any(os.path.exists(path) for path in config_paths)
-
- self.test_results['web_server'] = {
- 'status': 'PASS' if is_installed else 'WARN',
- 'web_server': web_server,
- 'is_installed': is_installed,
- 'config_paths': config_paths
- }
-
- print(f" ā
Web Server: {web_server}")
- print(f" {'ā
' if is_installed else 'ā ļø'} Installed: {is_installed}")
-
- except Exception as e:
- self.test_results['web_server'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_file_permissions(self):
- """Test file permissions and ownership"""
- print("\nš Testing File Permissions...")
-
- try:
- # Test if we can create files in plugin directory
- plugin_dir = "/home/cyberpanel/plugins"
- cyberpanel_dir = "/usr/local/CyberCP"
-
- can_create_plugin_dir = True
- can_create_cyberpanel_dir = True
-
- try:
- os.makedirs(plugin_dir, exist_ok=True)
- except PermissionError:
- can_create_plugin_dir = False
-
- try:
- os.makedirs(f"{cyberpanel_dir}/test", exist_ok=True)
- os.rmdir(f"{cyberpanel_dir}/test")
- except PermissionError:
- can_create_cyberpanel_dir = False
-
- self.test_results['file_permissions'] = {
- 'status': 'PASS' if can_create_plugin_dir and can_create_cyberpanel_dir else 'WARN',
- 'can_create_plugin_dir': can_create_plugin_dir,
- 'can_create_cyberpanel_dir': can_create_cyberpanel_dir,
- 'plugin_dir': plugin_dir,
- 'cyberpanel_dir': cyberpanel_dir
- }
-
- print(f" {'ā
' if can_create_plugin_dir else 'ā ļø'} Plugin Directory: {plugin_dir}")
- print(f" {'ā
' if can_create_cyberpanel_dir else 'ā ļø'} CyberPanel Directory: {cyberpanel_dir}")
-
- except Exception as e:
- self.test_results['file_permissions'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_network_connectivity(self):
- """Test network connectivity"""
- print("\nš Testing Network Connectivity...")
-
- try:
- # Test GitHub connectivity
- github_result = subprocess.run(['curl', '-s', '--connect-timeout', '10',
- 'https://github.com'],
- capture_output=True, text=True, timeout=15)
- github_available = github_result.returncode == 0
-
- # Test general internet connectivity
- internet_result = subprocess.run(['curl', '-s', '--connect-timeout', '10',
- 'https://www.google.com'],
- capture_output=True, text=True, timeout=15)
- internet_available = internet_result.returncode == 0
-
- self.test_results['network_connectivity'] = {
- 'status': 'PASS' if github_available and internet_available else 'WARN',
- 'github_available': github_available,
- 'internet_available': internet_available
- }
-
- print(f" {'ā
' if github_available else 'ā ļø'} GitHub: {github_available}")
- print(f" {'ā
' if internet_available else 'ā ļø'} Internet: {internet_available}")
-
- except Exception as e:
- self.test_results['network_connectivity'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def test_cyberpanel_integration(self):
- """Test CyberPanel integration"""
- print("\nā” Testing CyberPanel Integration...")
-
- try:
- cyberpanel_dir = "/usr/local/CyberCP"
-
- # Check if CyberPanel is installed
- cyberpanel_installed = os.path.exists(cyberpanel_dir)
-
- # Check if Django settings exist
- settings_file = f"{cyberpanel_dir}/cyberpanel/settings.py"
- settings_exist = os.path.exists(settings_file)
-
- # Check if URLs file exists
- urls_file = f"{cyberpanel_dir}/cyberpanel/urls.py"
- urls_exist = os.path.exists(urls_file)
-
- # Check if lscpd service exists
- lscpd_exists = os.path.exists("/usr/local/lscp/bin/lscpd")
-
- self.test_results['cyberpanel_integration'] = {
- 'status': 'PASS' if cyberpanel_installed and settings_exist and urls_exist else 'WARN',
- 'cyberpanel_installed': cyberpanel_installed,
- 'settings_exist': settings_exist,
- 'urls_exist': urls_exist,
- 'lscpd_exists': lscpd_exists
- }
-
- print(f" {'ā
' if cyberpanel_installed else 'ā ļø'} CyberPanel Installed: {cyberpanel_installed}")
- print(f" {'ā
' if settings_exist else 'ā ļø'} Settings File: {settings_exist}")
- print(f" {'ā
' if urls_exist else 'ā ļø'} URLs File: {urls_exist}")
- print(f" {'ā
' if lscpd_exists else 'ā ļø'} LSCPD Service: {lscpd_exists}")
-
- except Exception as e:
- self.test_results['cyberpanel_integration'] = {
- 'status': 'FAIL',
- 'error': str(e)
- }
- print(f" ā Error: {e}")
-
- def display_results(self):
- """Display test results summary"""
- print("\n" + "=" * 60)
- print("š COMPATIBILITY TEST RESULTS")
- print("=" * 60)
-
- total_tests = len(self.test_results)
- passed_tests = sum(1 for result in self.test_results.values() if result['status'] == 'PASS')
- warned_tests = sum(1 for result in self.test_results.values() if result['status'] == 'WARN')
- failed_tests = sum(1 for result in self.test_results.values() if result['status'] == 'FAIL')
-
- print(f"Total Tests: {total_tests}")
- print(f"ā
Passed: {passed_tests}")
- print(f"ā ļø Warnings: {warned_tests}")
- print(f"ā Failed: {failed_tests}")
-
- if failed_tests == 0:
- print("\nš All tests passed! The plugin is compatible with this OS.")
- elif warned_tests > 0 and failed_tests == 0:
- print("\nā ļø Some warnings detected. The plugin should work but may need attention.")
- else:
- print("\nā Some tests failed. The plugin may not work properly on this OS.")
-
- # Show detailed results
- print("\nš Detailed Results:")
- for test_name, result in self.test_results.items():
- status_icon = {'PASS': 'ā
', 'WARN': 'ā ļø', 'FAIL': 'ā'}[result['status']]
- print(f" {status_icon} {test_name.replace('_', ' ').title()}: {result['status']}")
- if 'error' in result:
- print(f" Error: {result['error']}")
-
- # Generate compatibility report
- self.generate_compatibility_report()
-
- def generate_compatibility_report(self):
- """Generate a compatibility report file"""
- try:
- report = {
- 'timestamp': time.time(),
- 'os_info': self.os_config.get_os_info(),
- 'test_results': self.test_results,
- 'compatibility_score': self.calculate_compatibility_score()
- }
-
- report_file = "compatibility_report.json"
- with open(report_file, 'w') as f:
- json.dump(report, f, indent=2)
-
- print(f"\nš Compatibility report saved to: {report_file}")
-
- except Exception as e:
- print(f"\nā ļø Could not save compatibility report: {e}")
-
- def calculate_compatibility_score(self):
- """Calculate overall compatibility score"""
- total_tests = len(self.test_results)
- if total_tests == 0:
- return 0
-
- score = 0
- for result in self.test_results.values():
- if result['status'] == 'PASS':
- score += 1
- elif result['status'] == 'WARN':
- score += 0.5
-
- return round((score / total_tests) * 100, 1)
-
-
-def main():
- """Main function"""
- tester = OSCompatibilityTester()
- results = tester.run_all_tests()
-
- # Exit with appropriate code
- failed_tests = sum(1 for result in results.values() if result['status'] == 'FAIL')
- if failed_tests > 0:
- sys.exit(1)
- else:
- sys.exit(0)
-
-
-if __name__ == "__main__":
- main()
diff --git a/testPlugin/urls.py b/testPlugin/urls.py
deleted file mode 100644
index 8c2a41a90..000000000
--- a/testPlugin/urls.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from django.urls import path
-from . import views
-
-urlpatterns = [
- path('', views.test_plugin_view, name='testPlugin'),
- path('info/', views.plugin_info_view, name='testPluginInfo'),
- path('settings/', views.settings_view, name='testPluginSettings'),
-]
diff --git a/testPlugin/views.py b/testPlugin/views.py
deleted file mode 100644
index 07bc88899..000000000
--- a/testPlugin/views.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from django.shortcuts import render, redirect
-from django.http import JsonResponse
-from functools import wraps
-
-def cyberpanel_login_required(view_func):
- """
- Custom decorator that checks for CyberPanel session userID
- """
- @wraps(view_func)
- def _wrapped_view(request, *args, **kwargs):
- try:
- userID = request.session['userID']
- # User is authenticated via CyberPanel session
- return view_func(request, *args, **kwargs)
- except KeyError:
- # Not logged in, redirect to login
- return redirect('/')
- return _wrapped_view
-
-@cyberpanel_login_required
-def test_plugin_view(request):
- """
- Main view for the test plugin
- """
- context = {
- 'plugin_name': 'Test Plugin',
- 'version': '1.0.0',
- 'description': 'A simple test plugin for CyberPanel'
- }
- return render(request, 'testPlugin/index.html', context)
-
-@cyberpanel_login_required
-def plugin_info_view(request):
- """
- API endpoint for plugin information
- """
- return JsonResponse({
- 'plugin_name': 'Test Plugin',
- 'version': '1.0.0',
- 'status': 'active',
- 'description': 'A simple test plugin for CyberPanel testing'
- })
-
-@cyberpanel_login_required
-def settings_view(request):
- """
- Settings page for the test plugin
- """
- context = {
- 'plugin_name': 'Test Plugin',
- 'version': '1.0.0',
- 'description': 'A simple test plugin for CyberPanel'
- }
- return render(request, 'testPlugin/settings.html', context)