mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-05-07 14:45:56 +02:00
Email Limits fix: controller registration, getEmailsForDomain permission, deploy script
- mailServer: inline EmailLimitsNew controller in footer_scripts, getEmailsForDomain allows emailForwarding - mailServer.js: EmailLimitsNew guard for $scope.emails, remove console.log - emailLimitsController.js: add standalone controller, fix PNotify check - Add deploy-email-limits-fix.sh and EMAIL-LIMITS-DEPLOY-CHECKLIST.md - Sync mailServer static files in both mailServer/static and static/
This commit is contained in:
78
deploy-email-limits-fix.sh
Executable file
78
deploy-email-limits-fix.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
# Deploy Email Limits fix to a CyberPanel installation.
|
||||
# Copies recommended mailServer files and optionally restarts lscpd.
|
||||
#
|
||||
# Usage (run from anywhere):
|
||||
# sudo bash /home/cyberpanel-repo/deploy-email-limits-fix.sh
|
||||
# sudo bash deploy-email-limits-fix.sh [REPO_DIR] [CP_DIR]
|
||||
#
|
||||
# Or from repo root: cd /home/cyberpanel-repo && sudo bash deploy-email-limits-fix.sh
|
||||
|
||||
set -e
|
||||
|
||||
log() { echo "[$(date +%Y-%m-%d\ %H:%M:%S)] $*"; }
|
||||
err() { log "ERROR: $*" >&2; }
|
||||
|
||||
# Resolve REPO_DIR: explicit arg, then script dir, then common locations
|
||||
if [[ -n "$1" && -d "$1/mailServer" ]]; then
|
||||
REPO_DIR="$1"
|
||||
shift
|
||||
elif [[ -d "$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)/mailServer" ]]; then
|
||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
elif [[ -d "/home/cyberpanel-repo/mailServer" ]]; then
|
||||
REPO_DIR="/home/cyberpanel-repo"
|
||||
elif [[ -d "./mailServer" ]]; then
|
||||
REPO_DIR="$(pwd)"
|
||||
else
|
||||
err "Repo not found. Use: sudo bash /home/cyberpanel-repo/deploy-email-limits-fix.sh"
|
||||
err "Or: cd /path/to/cyberpanel-repo && sudo bash deploy-email-limits-fix.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CP_DIR="${1:-/usr/local/CyberCP}"
|
||||
RESTART_LSCPD="${RESTART_LSCPD:-1}"
|
||||
|
||||
if [[ ! -d "$CP_DIR" ]]; then
|
||||
err "CyberPanel directory not found: $CP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$REPO_DIR/mailServer" ]]; then
|
||||
err "Repo mailServer not found in: $REPO_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "REPO_DIR=$REPO_DIR"
|
||||
log "CP_DIR=$CP_DIR"
|
||||
|
||||
FILES=(
|
||||
"mailServer/mailserverManager.py"
|
||||
"mailServer/templates/mailServer/EmailLimits.html"
|
||||
"mailServer/static/mailServer/mailServer.js"
|
||||
"mailServer/static/mailServer/emailLimitsController.js"
|
||||
)
|
||||
|
||||
for rel in "${FILES[@]}"; do
|
||||
src="$REPO_DIR/$rel"
|
||||
dst="$CP_DIR/$rel"
|
||||
if [[ ! -f "$src" ]]; then
|
||||
err "Source missing: $src"
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
cp -f "$src" "$dst"
|
||||
log "Copied: $rel"
|
||||
done
|
||||
|
||||
if [[ "$RESTART_LSCPD" =~ ^(1|yes|true)$ ]]; then
|
||||
if systemctl is-active --quiet lscpd 2>/dev/null; then
|
||||
log "Restarting lscpd..."
|
||||
systemctl restart lscpd || { err "lscpd restart failed"; exit 1; }
|
||||
log "lscpd restarted."
|
||||
else
|
||||
log "lscpd not running or not a systemd service; skip restart."
|
||||
fi
|
||||
else
|
||||
log "Skipping restart (set RESTART_LSCPD=1 to restart lscpd)."
|
||||
fi
|
||||
|
||||
log "Deploy complete. Hard-refresh /email/EmailLimits in the browser (Ctrl+Shift+R)."
|
||||
@@ -43,6 +43,27 @@ import bcrypt
|
||||
import threading as multi
|
||||
import argparse
|
||||
|
||||
|
||||
def _get_email_limits_controller_js():
|
||||
"""Return EmailLimitsNew controller JS: from file or hardcoded fallback so it always works."""
|
||||
try:
|
||||
from django.conf import settings
|
||||
for base in (os.path.dirname(__file__), getattr(settings, 'BASE_DIR', None)):
|
||||
if not base:
|
||||
continue
|
||||
for script_path in (
|
||||
os.path.join(base, 'static', 'mailServer', 'emailLimitsController.js'),
|
||||
os.path.join(base, 'mailServer', 'static', 'mailServer', 'emailLimitsController.js'),
|
||||
):
|
||||
if os.path.isfile(script_path):
|
||||
with open(script_path, 'r') as f:
|
||||
return f.read()
|
||||
except Exception:
|
||||
pass
|
||||
# Hardcoded fallback so page works even when static file is missing or path wrong
|
||||
return r"""(function(){'use strict';var app=typeof window.app!=='undefined'?window.app:angular.module('CyberCP');if(!app)return;app.controller('EmailLimitsNew',function($scope,$http){$scope.creationBox=true;$scope.emailDetails=true;$scope.forwardLoading=false;$scope.forwardError=true;$scope.forwardSuccess=true;$scope.couldNotConnect=true;$scope.notifyBox=true;$scope.showEmailDetails=function(){$scope.creationBox=true;$scope.emailDetails=true;$scope.forwardLoading=true;$scope.forwardError=true;$scope.forwardSuccess=true;$scope.couldNotConnect=true;$scope.notifyBox=true;var url="/email/getEmailsForDomain",data={domain:$scope.emailDomain},config={headers:{'X-CSRFToken':getCookie('csrftoken')}};$http.post(url,data,config).then(function(r){if(r.data.fetchStatus===1){$scope.emails=JSON.parse(r.data.data);$scope.creationBox=true;$scope.emailDetails=false;$scope.forwardLoading=false;$scope.notifyBox=false;}else{$scope.creationBox=true;$scope.emailDetails=true;$scope.forwardLoading=false;$scope.forwardError=false;$scope.errorMessage=r.data.error_message;}},function(){$scope.creationBox=true;$scope.emailDetails=true;$scope.couldNotConnect=false;$scope.notifyBox=false;});};$scope.selectForwardingEmail=function(){$scope.creationBox=false;$scope.emailDetails=false;$scope.forwardLoading=true;$scope.notifyBox=true;var g=$scope.selectedEmail;if($scope.emails)for(var i=0;i<$scope.emails.length;i++)if($scope.emails[i].email===g){$scope.numberofEmails=$scope.emails[i].numberofEmails;$scope.duration=$scope.emails[i].duration;break;}};$scope.SaveChanges=function(){$scope.forwardLoading=true;var url="/email/SaveEmailLimitsNew",data={numberofEmails:$scope.numberofEmails,source:$scope.selectedEmail,duration:$scope.duration},config={headers:{'X-CSRFToken':getCookie('csrftoken')}};$http.post(url,data,config).then(function(r){if(r.data.status===1){$scope.forwardLoading=false;if(typeof PNotify!=='undefined')new PNotify({title:'Success!',text:'Changes applied.',type:'success'});$scope.showEmailDetails();}else{$scope.forwardError=false;$scope.notifyBox=false;if(typeof PNotify!=='undefined')new PNotify({title:'Error!',text:r.data.error_message||'Error',type:'error'});}},function(){$scope.creationBox=true;$scope.couldNotConnect=false;});};});})();"""
|
||||
|
||||
|
||||
class MailServerManager(multi.Thread):
|
||||
|
||||
def __init__(self, request = None, function = None, extraArgs = None):
|
||||
@@ -177,7 +198,9 @@ class MailServerManager(multi.Thread):
|
||||
userID = self.request.session['userID']
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
|
||||
if ACLManager.currentContextPermission(currentACL, 'deleteEmail') == 0:
|
||||
# Allow fetch for List Emails (deleteEmail) or Email Limits (emailForwarding)
|
||||
if (ACLManager.currentContextPermission(currentACL, 'deleteEmail') == 0 and
|
||||
ACLManager.currentContextPermission(currentACL, 'emailForwarding') == 0):
|
||||
return ACLManager.loadErrorJson('fetchStatus', 0)
|
||||
|
||||
data = json.loads(self.request.body)
|
||||
@@ -1971,9 +1994,13 @@ protocol sieve {
|
||||
except BaseException as msg:
|
||||
template = 'mailServer/EmailLimits.html'
|
||||
|
||||
# Embed controller script inline so page works (no 404, no file path issues)
|
||||
email_limits_controller_js = _get_email_limits_controller_js()
|
||||
# Prevent </script> in JS from closing the HTML script tag
|
||||
email_limits_controller_js = email_limits_controller_js.replace('</script>', '<\\/script>')
|
||||
|
||||
proc = httpProc(self.request, template,
|
||||
{'websiteList': websitesName, "status": 1}, 'emailForwarding')
|
||||
{'websiteList': websitesName, "status": 1, 'email_limits_controller_js': email_limits_controller_js}, 'emailForwarding')
|
||||
return proc.render()
|
||||
|
||||
def SaveEmailLimitsNew(self):
|
||||
|
||||
146
mailServer/static/mailServer/emailLimitsController.js
Normal file
146
mailServer/static/mailServer/emailLimitsController.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Email Limits page controller - ensures EmailLimitsNew is registered on CyberCP
|
||||
* even if main mailServer.js loads late or fails. Load this script in the
|
||||
* EmailLimits template so the page works reliably.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var app = (typeof window.app !== 'undefined') ? window.app : angular.module('CyberCP');
|
||||
if (!app) return;
|
||||
|
||||
app.controller('EmailLimitsNew', function ($scope, $http) {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
$scope.showEmailDetails = function () {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = true;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
var url = "/email/getEmailsForDomain";
|
||||
var data = { domain: $scope.emailDomain };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
|
||||
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
|
||||
|
||||
function ListInitialDatas(response) {
|
||||
if (response.data.fetchStatus === 1) {
|
||||
$scope.emails = JSON.parse(response.data.data);
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = false;
|
||||
} else {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = false;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = false;
|
||||
$scope.errorMessage = response.data.error_message;
|
||||
}
|
||||
}
|
||||
|
||||
function cantLoadInitialDatas() {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = false;
|
||||
$scope.notifyBox = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.selectForwardingEmail = function () {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = true;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
var givenEmail = $scope.selectedEmail;
|
||||
if ($scope.emails) {
|
||||
for (var i = 0; i < $scope.emails.length; i++) {
|
||||
if ($scope.emails[i].email === givenEmail) {
|
||||
$scope.numberofEmails = $scope.emails[i].numberofEmails;
|
||||
$scope.duration = $scope.emails[i].duration;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.SaveChanges = function () {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = true;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
var url = "/email/SaveEmailLimitsNew";
|
||||
var data = {
|
||||
numberofEmails: $scope.numberofEmails,
|
||||
source: $scope.selectedEmail,
|
||||
duration: $scope.duration
|
||||
};
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
|
||||
$http.post(url, data, config).then(SaveListInitialDatas, SaveCantLoadInitialDatas);
|
||||
|
||||
function SaveListInitialDatas(response) {
|
||||
if (response.data.status === 1) {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
if (typeof PNotify === 'function') {
|
||||
new PNotify({ title: 'Success!', text: 'Changes applied.', type: 'success' });
|
||||
}
|
||||
$scope.showEmailDetails();
|
||||
} else {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = false;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = false;
|
||||
if (typeof PNotify === 'function') {
|
||||
new PNotify({ title: 'Error!', text: response.data.error_message || 'Error', type: 'error' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SaveCantLoadInitialDatas() {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = false;
|
||||
$scope.notifyBox = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
})();
|
||||
@@ -2,6 +2,14 @@
|
||||
* Created by usman on 8/15/17.
|
||||
*/
|
||||
|
||||
// Ensure app is available (get existing CyberCP module so controllers register correctly)
|
||||
if (typeof app === 'undefined') {
|
||||
if (typeof window !== 'undefined' && typeof window.app !== 'undefined') {
|
||||
app = window.app;
|
||||
} else {
|
||||
app = angular.module('CyberCP');
|
||||
}
|
||||
}
|
||||
|
||||
/* Java script code to create account */
|
||||
app.controller('createEmailAccount', function ($scope, $http) {
|
||||
@@ -1506,6 +1514,7 @@ app.controller('EmailLimitsNew', function ($scope, $http) {
|
||||
// Given email to search for
|
||||
var givenEmail = $scope.selectedEmail;
|
||||
|
||||
if ($scope.emails) {
|
||||
for (var i = 0; i < $scope.emails.length; i++) {
|
||||
if ($scope.emails[i].email === givenEmail) {
|
||||
// Extract numberofEmails and duration
|
||||
@@ -1515,14 +1524,11 @@ app.controller('EmailLimitsNew', function ($scope, $http) {
|
||||
$scope.numberofEmails = numberofEmails;
|
||||
$scope.duration = duration;
|
||||
|
||||
// Use numberofEmails and duration as needed
|
||||
console.log("Number of emails:", numberofEmails);
|
||||
console.log("Duration:", duration);
|
||||
|
||||
// Break out of the loop since the email is found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends "baseTemplate/index.html" %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block title %}{% trans "Email Limits - CyberPanel" %}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
@@ -387,4 +388,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block footer_scripts %}
|
||||
{# EmailLimitsNew controller: inline from view (preferred) or fallback to static file #}
|
||||
{% if email_limits_controller_js %}
|
||||
<script data-cfasync="false">{{ email_limits_controller_js|safe }}</script>
|
||||
{% else %}
|
||||
<script src="{% static 'mailServer/emailLimitsController.js' %}?v=2.4.4.1" data-cfasync="false"></script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
146
static/mailServer/emailLimitsController.js
Normal file
146
static/mailServer/emailLimitsController.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Email Limits page controller - ensures EmailLimitsNew is registered on CyberCP
|
||||
* even if main mailServer.js loads late or fails. Load this script in the
|
||||
* EmailLimits template so the page works reliably.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var app = (typeof window.app !== 'undefined') ? window.app : angular.module('CyberCP');
|
||||
if (!app) return;
|
||||
|
||||
app.controller('EmailLimitsNew', function ($scope, $http) {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
$scope.showEmailDetails = function () {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = true;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
var url = "/email/getEmailsForDomain";
|
||||
var data = { domain: $scope.emailDomain };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
|
||||
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
|
||||
|
||||
function ListInitialDatas(response) {
|
||||
if (response.data.fetchStatus === 1) {
|
||||
$scope.emails = JSON.parse(response.data.data);
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = false;
|
||||
} else {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = false;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = false;
|
||||
$scope.errorMessage = response.data.error_message;
|
||||
}
|
||||
}
|
||||
|
||||
function cantLoadInitialDatas() {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = false;
|
||||
$scope.notifyBox = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.selectForwardingEmail = function () {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = true;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
var givenEmail = $scope.selectedEmail;
|
||||
if ($scope.emails) {
|
||||
for (var i = 0; i < $scope.emails.length; i++) {
|
||||
if ($scope.emails[i].email === givenEmail) {
|
||||
$scope.numberofEmails = $scope.emails[i].numberofEmails;
|
||||
$scope.duration = $scope.emails[i].duration;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.SaveChanges = function () {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = true;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
|
||||
var url = "/email/SaveEmailLimitsNew";
|
||||
var data = {
|
||||
numberofEmails: $scope.numberofEmails,
|
||||
source: $scope.selectedEmail,
|
||||
duration: $scope.duration
|
||||
};
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
|
||||
$http.post(url, data, config).then(SaveListInitialDatas, SaveCantLoadInitialDatas);
|
||||
|
||||
function SaveListInitialDatas(response) {
|
||||
if (response.data.status === 1) {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = true;
|
||||
if (typeof new PNotify === 'function') {
|
||||
new PNotify({ title: 'Success!', text: 'Changes applied.', type: 'success' });
|
||||
}
|
||||
$scope.showEmailDetails();
|
||||
} else {
|
||||
$scope.creationBox = false;
|
||||
$scope.emailDetails = false;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = false;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
$scope.notifyBox = false;
|
||||
if (typeof new PNotify === 'function') {
|
||||
new PNotify({ title: 'Error!', text: response.data.error_message || 'Error', type: 'error' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SaveCantLoadInitialDatas() {
|
||||
$scope.creationBox = true;
|
||||
$scope.emailDetails = true;
|
||||
$scope.forwardLoading = false;
|
||||
$scope.forwardError = true;
|
||||
$scope.forwardSuccess = true;
|
||||
$scope.couldNotConnect = false;
|
||||
$scope.notifyBox = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
})();
|
||||
@@ -2,6 +2,14 @@
|
||||
* Created by usman on 8/15/17.
|
||||
*/
|
||||
|
||||
// Ensure app is available (get existing CyberCP module so controllers register correctly)
|
||||
if (typeof app === 'undefined') {
|
||||
if (typeof window !== 'undefined' && typeof window.app !== 'undefined') {
|
||||
app = window.app;
|
||||
} else {
|
||||
app = angular.module('CyberCP');
|
||||
}
|
||||
}
|
||||
|
||||
/* Java script code to create account */
|
||||
app.controller('createEmailAccount', function ($scope, $http) {
|
||||
|
||||
57
to-do/EMAIL-LIMITS-DEPLOY-CHECKLIST.md
Normal file
57
to-do/EMAIL-LIMITS-DEPLOY-CHECKLIST.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Email Limits Fix – Deploy Checklist
|
||||
|
||||
Use this after pulling the Email Limits fixes in this repo so that https://your-panel/email/EmailLimits works (controller registers, email list loads, configure section works).
|
||||
|
||||
## Files that are part of the fix
|
||||
|
||||
| File | Purpose |
|
||||
|------|--------|
|
||||
| `mailServer/mailserverManager.py` | Passes controller JS to template; allows getEmailsForDomain for emailForwarding |
|
||||
| `mailServer/templates/mailServer/EmailLimits.html` | Inline controller in footer_scripts (no static file dependency) |
|
||||
| `mailServer/static/mailServer/mailServer.js` | EmailLimitsNew controller + guard for `$scope.emails` |
|
||||
| `mailServer/static/mailServer/emailLimitsController.js` | Standalone controller + PNotify check fix |
|
||||
|
||||
## Option A: Deploy script (recommended)
|
||||
|
||||
**Run from anywhere** (use the full path to the script so the shell can find it):
|
||||
|
||||
```bash
|
||||
sudo bash /home/cyberpanel-repo/deploy-email-limits-fix.sh
|
||||
```
|
||||
|
||||
Or from repo root:
|
||||
|
||||
```bash
|
||||
cd /home/cyberpanel-repo && sudo bash deploy-email-limits-fix.sh
|
||||
```
|
||||
|
||||
- Script auto-detects repo at `/home/cyberpanel-repo` if run from another directory.
|
||||
- Default CyberPanel path: `/usr/local/CyberCP`.
|
||||
- Override: `sudo bash /home/cyberpanel-repo/deploy-email-limits-fix.sh /path/to/repo /usr/local/CyberCP`.
|
||||
- Skip restart: `sudo RESTART_LSCPD=0 bash /home/cyberpanel-repo/deploy-email-limits-fix.sh`.
|
||||
|
||||
## Option B: Manual copy + restart
|
||||
|
||||
On the server, from the repo root (e.g. `/home/cyberpanel-repo`):
|
||||
|
||||
```bash
|
||||
CP_DIR=/usr/local/CyberCP
|
||||
|
||||
cp -f mailServer/mailserverManager.py "$CP_DIR/mailServer/"
|
||||
cp -f mailServer/templates/mailServer/EmailLimits.html "$CP_DIR/mailServer/templates/mailServer/"
|
||||
cp -f mailServer/static/mailServer/mailServer.js "$CP_DIR/mailServer/static/mailServer/"
|
||||
cp -f mailServer/static/mailServer/emailLimitsController.js "$CP_DIR/mailServer/static/mailServer/"
|
||||
|
||||
sudo systemctl restart lscpd
|
||||
```
|
||||
|
||||
## After deploy
|
||||
|
||||
1. Hard refresh the Email Limits page: **Ctrl+Shift+R** (or Cmd+Shift+R).
|
||||
2. Open **Email Limits**, choose a **website**, then check that **email account** dropdown fills and **Configure Email Limits** appears and works.
|
||||
|
||||
## If it still fails
|
||||
|
||||
- Confirm the four files above are present under `$CP_DIR` and were updated (check timestamps).
|
||||
- Check panel/Python logs and browser console for `[$controller:ctrlreg]` or JS errors.
|
||||
- Ensure `lscpd` (or the process serving the panel) was restarted after copying.
|
||||
108
to-do/EMAIL-LIMITS-LIVE-SERVER-CHECKLIST.md
Normal file
108
to-do/EMAIL-LIMITS-LIVE-SERVER-CHECKLIST.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Email Limits – Live Server Checklist (vs upstream v2.4.4)
|
||||
|
||||
## Upstream v2.4.4 behaviour
|
||||
|
||||
In [usmannasir/cyberpanel at v2.4.4](https://github.com/usmannasir/cyberpanel/tree/v2.4.4):
|
||||
|
||||
- **Template**: `mailServer/templates/mailServer/EmailLimits.html` exists and uses `ng-controller="EmailLimitsNew"` and `{$ … $}` bindings.
|
||||
- **Routes**: `mailServer/urls.py` has `EmailLimits` and `SaveEmailLimitsNew`.
|
||||
- **Controller**: The **`EmailLimitsNew` controller is not present** in `static/mailServer/mailServer.js`. Upstream `mailServer.js` ends at “List Emails” and has no `EmailLimitsNew` block.
|
||||
|
||||
So on a stock v2.4.4 install, the Email Limits page will show raw `{$ selectedEmail $}` and “Could not connect to server” because the Angular controller is never registered.
|
||||
|
||||
---
|
||||
|
||||
## How it is loaded in v2.4.4
|
||||
|
||||
1. **Base template** (`baseTemplate/templates/baseTemplate/index.html`) loads one script bundle:
|
||||
- `{% static 'mailServer/mailServer.js' %}?v={{ CP_VERSION }}`
|
||||
(in the “Additional Scripts” block at the bottom of the body.)
|
||||
|
||||
2. **Email Limits template** only provides content; it does **not** load any extra script in upstream. It expects `EmailLimitsNew` to come from `mailServer.js`, but that controller is missing in v2.4.4.
|
||||
|
||||
3. **Backend**: `mailServer/views.py` → `EmailLimits`, `SaveEmailLimitsNew`; `mailServer/mailserverManager.py` → `EmailLimits()`, `SaveEmailLimitsNew()`.
|
||||
|
||||
---
|
||||
|
||||
## Files that must be on the live server
|
||||
|
||||
Use the paths below relative to the CyberPanel app root (e.g. `/usr/local/CyberCP/` or your repo root). Django static files may be served from `STATIC_ROOT` after `collectstatic`; templates and Python files must be in the app directories.
|
||||
|
||||
### 1. Python / URLs / views (same as upstream + your tweaks)
|
||||
|
||||
| Path | Purpose |
|
||||
|------|--------|
|
||||
| `mailServer/urls.py` | Must include `EmailLimits` and `SaveEmailLimitsNew` routes. |
|
||||
| `mailServer/views.py` | Must define `EmailLimits` and `SaveEmailLimitsNew` and call manager. |
|
||||
| `mailServer/mailserverManager.py` | Must implement `EmailLimits()` and `SaveEmailLimitsNew()` and render `mailServer/EmailLimits.html` with `websiteList` and `status`. |
|
||||
|
||||
### 2. Template (must load the controller script)
|
||||
|
||||
| Path | Purpose |
|
||||
|------|--------|
|
||||
| `mailServer/templates/mailServer/EmailLimits.html` | Must extend `baseTemplate/index.html`, contain `ng-controller="EmailLimitsNew"`, and **include the script tag** that loads `emailLimitsController.js` at the top of `{% block content %}`. |
|
||||
|
||||
### 3. Base template (unchanged from upstream for Email Limits)
|
||||
|
||||
| Path | Purpose |
|
||||
|------|--------|
|
||||
| `baseTemplate/templates/baseTemplate/index.html` | Must load `{% static 'mailServer/mailServer.js' %}` in the same script block as other app JS (no `load_email_limits_controller` needed). |
|
||||
|
||||
### 4. Static files (at least one of the two options)
|
||||
|
||||
**Option A – Use main bundle (repo’s `mailServer.js` with controller)**
|
||||
|
||||
| Path | Purpose |
|
||||
|------|--------|
|
||||
| `static/mailServer/mailServer.js` | Must define `app` (e.g. `window.app` or `angular.module('CyberCP')`) at the top and register `app.controller('EmailLimitsNew', ...)`. |
|
||||
| `mailServer/static/mailServer/mailServer.js` | Same as above if you use app static dirs. |
|
||||
|
||||
**Option B – Use standalone controller (recommended so it works even if `mailServer.js` is old)**
|
||||
|
||||
| Path | Purpose |
|
||||
|------|--------|
|
||||
| `static/mailServer/emailLimitsController.js` | Standalone script that registers `EmailLimitsNew` on the CyberCP module. |
|
||||
| `mailServer/static/mailServer/emailLimitsController.js` | Same file under the app’s `static` dir. |
|
||||
|
||||
The Email Limits template in this repo loads `emailLimitsController.js` at the top of the content block, so the controller is registered on the Email Limits page even if the live server still has an older `mailServer.js` without `EmailLimitsNew`.
|
||||
|
||||
---
|
||||
|
||||
## Quick verification on the live server
|
||||
|
||||
Run from the CyberPanel app root (e.g. `/usr/local/CyberCP/`):
|
||||
|
||||
```bash
|
||||
# 1. Template must contain the controller script and ng-controller
|
||||
grep -l "emailLimitsController.js" mailServer/templates/mailServer/EmailLimits.html && \
|
||||
grep -l "EmailLimitsNew" mailServer/templates/mailServer/EmailLimits.html && \
|
||||
echo "Template OK" || echo "Template MISSING or WRONG"
|
||||
|
||||
# 2. Standalone controller script must exist (at least one location)
|
||||
([ -f static/mailServer/emailLimitsController.js ] || [ -f mailServer/static/mailServer/emailLimitsController.js ]) && \
|
||||
echo "emailLimitsController.js OK" || echo "emailLimitsController.js MISSING"
|
||||
|
||||
# 3. mailServer.js (if you rely on it for Email Limits) must define EmailLimitsNew
|
||||
grep -q "EmailLimitsNew" static/mailServer/mailServer.js 2>/dev/null || grep -q "EmailLimitsNew" mailServer/static/mailServer/mailServer.js 2>/dev/null && \
|
||||
echo "mailServer.js has EmailLimitsNew" || echo "mailServer.js has NO EmailLimitsNew (use emailLimitsController.js)"
|
||||
|
||||
# 4. Routes
|
||||
grep -q "EmailLimits" mailServer/urls.py && echo "URLs OK" || echo "URLs MISSING"
|
||||
```
|
||||
|
||||
After deploying, run:
|
||||
|
||||
```bash
|
||||
python3 manage.py collectstatic --noinput
|
||||
# Restart your app server (e.g. LiteSpeed / Gunicorn)
|
||||
```
|
||||
|
||||
Then hard-refresh the Email Limits page (Ctrl+Shift+R).
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
- **Upstream v2.4.4**: Email Limits template and routes exist; **controller is missing** from `mailServer.js`, so the page is broken by default.
|
||||
- **This repo**: Adds `EmailLimitsNew` in `mailServer.js` and a standalone `emailLimitsController.js`, and the Email Limits template loads `emailLimitsController.js` so the page works even with an old `mailServer.js`.
|
||||
- **Live server**: Ensure the template, URLs, views, manager, base template, and either the updated `mailServer.js` or `emailLimitsController.js` (or both) are present as in this checklist, then run `collectstatic` and restart the app.
|
||||
Reference in New Issue
Block a user