Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b87fdcc3f | |||
| a2275f4444 | |||
| 798d3fcdb5 | |||
|
|
9aa8378599 | ||
|
|
f0c28a4961 | ||
|
|
a46223e5ac | ||
| 98250f2f4c |
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
41
.github/workflows/publish-release.yml
vendored
41
.github/workflows/publish-release.yml
vendored
@@ -1,19 +1,38 @@
|
|||||||
---
|
# .github/workflows/semantic-versioning-release.yml
|
||||||
name: Publish Release
|
name: Automated Semantic Versioning Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # for creating tags and releases
|
||||||
|
issues: write # for commenting on issues
|
||||||
|
pull-requests: write # for commenting on PRs
|
||||||
steps:
|
steps:
|
||||||
- name: Publish Release
|
- name: Checkout code
|
||||||
uses: ncipollo/release-action@v1
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{secrets.GITHUB_TOKEN}}
|
# This is required to analyze the full commit history
|
||||||
draft: false
|
fetch-depth: 0
|
||||||
prerelease: false
|
|
||||||
name: "0.0.${{ github.run_number }}"
|
- name: Automated Semantic Release
|
||||||
tag: "0.0.${{ github.run_number }}"
|
# This action wraps the popular semantic-release tool
|
||||||
body: "Release 0.0.${{ github.run_number }}"
|
uses: cycjimmy/semantic-release-action@v4
|
||||||
|
with:
|
||||||
|
# You can specify the branches to release from
|
||||||
|
branch: main
|
||||||
|
env:
|
||||||
|
# GITHUB_TOKEN is required for authentication
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# To make this work, you must follow the Conventional Commits specification.
|
||||||
|
# Examples:
|
||||||
|
# - fix: correct a typo in the documentation
|
||||||
|
# - feat: add a new user authentication endpoint
|
||||||
|
# - feat(api): add rate limiting
|
||||||
|
# BREAKING CHANGE: The API now returns 429 when rate limit is exceeded.
|
||||||
|
|||||||
61
README.md
61
README.md
@@ -5,7 +5,8 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
This module requires VirtFusion v1.7.3 or higher as this is what it's based on. Please refer to the official [documenataion](https://docs.virtfusion.com/integrations/whmcs).
|
This module requires VirtFusion v1.7.3 or higher as this is what it's based on. Please refer to the
|
||||||
|
official [documentation](https://docs.virtfusion.com/integrations/whmcs).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -22,60 +23,8 @@ each product you want to use this module with.
|
|||||||
| Initial Operating System | Text Box | Set to whatever you want | Leave Blank | Leave Blank | :x: | :x: | :white_check_mark: | :x: |
|
| Initial Operating System | Text Box | Set to whatever you want | Leave Blank | Leave Blank | :x: | :x: | :white_check_mark: | :x: |
|
||||||
| Initial SSH Key | Text Box | Set to whatever you want | Leave Blank | Leave Blank | :x: | :x: | :white_check_mark: | :x: |
|
| Initial SSH Key | Text Box | Set to whatever you want | Leave Blank | Leave Blank | :x: | :x: | :white_check_mark: | :x: |
|
||||||
|
|
||||||
You can run this SQL query to create the custom fields:
|
You can run this SQL query to create the custom fields. Run the SQL from this [file](modify.sql) or copy the contents
|
||||||
|
from it.
|
||||||
```sql
|
|
||||||
-- Insert records for Initial Operating System if they don't already exist
|
|
||||||
INSERT INTO tblcustomfields
|
|
||||||
(type, relid, fieldname, fieldtype, description, fieldoptions, regexpr, adminonly, required, showorder, showinvoice,
|
|
||||||
sortorder, created_at, updated_at)
|
|
||||||
SELECT 'product',
|
|
||||||
id,
|
|
||||||
'Initial Operating System',
|
|
||||||
'text',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'on',
|
|
||||||
'',
|
|
||||||
0,
|
|
||||||
UTC_TIMESTAMP(),
|
|
||||||
UTC_TIMESTAMP()
|
|
||||||
FROM tblproducts
|
|
||||||
WHERE servertype = 'VirtFusionDirect'
|
|
||||||
AND NOT EXISTS (SELECT 1
|
|
||||||
FROM tblcustomfields
|
|
||||||
WHERE fieldname = 'Initial Operating System'
|
|
||||||
AND relid = tblproducts.id);
|
|
||||||
|
|
||||||
-- Insert records for Initial SSH Key if they don't already exist
|
|
||||||
INSERT INTO tblcustomfields
|
|
||||||
(type, relid, fieldname, fieldtype, description, fieldoptions, regexpr, adminonly, required, showorder, showinvoice,
|
|
||||||
sortorder, created_at, updated_at)
|
|
||||||
SELECT 'product',
|
|
||||||
id,
|
|
||||||
'Initial SSH Key',
|
|
||||||
'text',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'on',
|
|
||||||
'',
|
|
||||||
0,
|
|
||||||
UTC_TIMESTAMP(),
|
|
||||||
UTC_TIMESTAMP()
|
|
||||||
FROM tblproducts
|
|
||||||
WHERE servertype = 'VirtFusionDirect'
|
|
||||||
AND NOT EXISTS (SELECT 1
|
|
||||||
FROM tblcustomfields
|
|
||||||
WHERE fieldname = 'Initial SSH Key'
|
|
||||||
AND relid = tblproducts.id);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## What does this module change?
|
## What does this module change?
|
||||||
|
|
||||||
@@ -86,4 +35,4 @@ This module changes the following things:
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [ ] Add post checkout checks to ensure the user has selected an operating system and added a ssh key.
|
- [ ] Add post checkout checks to ensure the user has selected an operating system and added a ssh key.
|
||||||
|
|||||||
49
modify.sql
Normal file
49
modify.sql
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
-- Insert records for Initial Operating System if they don't already exist
|
||||||
|
INSERT INTO tblcustomfields
|
||||||
|
(type, relid, fieldname, fieldtype, description, fieldoptions, regexpr, adminonly, required, showorder, showinvoice,
|
||||||
|
sortorder, created_at, updated_at)
|
||||||
|
SELECT 'product',
|
||||||
|
id,
|
||||||
|
'Initial Operating System',
|
||||||
|
'text',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'on',
|
||||||
|
'',
|
||||||
|
0,
|
||||||
|
UTC_TIMESTAMP(),
|
||||||
|
UTC_TIMESTAMP()
|
||||||
|
FROM tblproducts
|
||||||
|
WHERE servertype = 'VirtFusionDirect'
|
||||||
|
AND NOT EXISTS (SELECT 1
|
||||||
|
FROM tblcustomfields
|
||||||
|
WHERE fieldname = 'Initial Operating System'
|
||||||
|
AND relid = tblproducts.id);
|
||||||
|
|
||||||
|
-- Insert records for Initial SSH Key if they don't already exist
|
||||||
|
INSERT INTO tblcustomfields
|
||||||
|
(type, relid, fieldname, fieldtype, description, fieldoptions, regexpr, adminonly, required, showorder, showinvoice,
|
||||||
|
sortorder, created_at, updated_at)
|
||||||
|
SELECT 'product',
|
||||||
|
id,
|
||||||
|
'Initial SSH Key',
|
||||||
|
'text',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'on',
|
||||||
|
'',
|
||||||
|
0,
|
||||||
|
UTC_TIMESTAMP(),
|
||||||
|
UTC_TIMESTAMP()
|
||||||
|
FROM tblproducts
|
||||||
|
WHERE servertype = 'VirtFusionDirect'
|
||||||
|
AND NOT EXISTS (SELECT 1
|
||||||
|
FROM tblcustomfields
|
||||||
|
WHERE fieldname = 'Initial SSH Key'
|
||||||
|
AND relid = tblproducts.id);
|
||||||
@@ -27,7 +27,7 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
|
|||||||
foreach ($templates_data['data'] as $osCategory) {
|
foreach ($templates_data['data'] as $osCategory) {
|
||||||
foreach ($osCategory['templates'] as $template) {
|
foreach ($osCategory['templates'] as $template) {
|
||||||
$optionValue = $template['id'];
|
$optionValue = $template['id'];
|
||||||
$optionLabel = $template['name'] . " " . $template['version'] . " " . $template['variant'];
|
$optionLabel = $template['name']." ".$template['version']." ".$template['variant'];
|
||||||
$dropdownOptions[] = ['id' => $optionValue, 'name' => $optionLabel];
|
$dropdownOptions[] = ['id' => $optionValue, 'name' => $optionLabel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,18 +65,20 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
|
|||||||
return "
|
return "
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
var osTemplates = " . json_encode($dropdownOptions) . ";
|
let osTemplates = ".json_encode($dropdownOptions, JSON_THROW_ON_ERROR).";
|
||||||
var sshKeys = " . json_encode($sshKeysOptions) . ";
|
let sshKeys = ".json_encode($sshKeysOptions, JSON_THROW_ON_ERROR).";
|
||||||
|
|
||||||
var osInputField = document.querySelector('[name=\"customfield[" . ($osID[0] ?? null) . "]\"]');
|
const osInputField = document.querySelector('[name=\"customfield[".($osID[0] ?? null)."]\"]');
|
||||||
var sshInputField = document.querySelector('[name=\"customfield[" . ($sshID[0] ?? null) . "]\"]');
|
const osInputLabel = document.querySelector('[for=\"customfield".($osID[0] ?? null)."\"]');
|
||||||
|
const sshInputField = document.querySelector('[name=\"customfield[".($sshID[0] ?? null)."]\"]');
|
||||||
|
const sshInputLabel = document.querySelector('[for=\"customfield".($sshID[0] ?? null)."\"]');
|
||||||
|
|
||||||
// Create dropdown options menu, then add it to the DOM then on change, update the regular input.
|
// Create dropdown options menu, then add it to the DOM then on change, update the regular input.
|
||||||
var osSelect = document.createElement('select');
|
let osSelect = document.createElement('select');
|
||||||
osSelect.className = 'form-control';
|
osSelect.className = 'form-control';
|
||||||
|
|
||||||
osTemplates.forEach(function(template) {
|
osTemplates.forEach(function(template) {
|
||||||
var option = document.createElement('option');
|
let option = document.createElement('option');
|
||||||
option.value = template.id;
|
option.value = template.id;
|
||||||
option.text = template.name;
|
option.text = template.name;
|
||||||
osSelect.appendChild(option);
|
osSelect.appendChild(option);
|
||||||
@@ -95,11 +97,11 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
|
|||||||
|
|
||||||
if (sshKeys.length > 0) {
|
if (sshKeys.length > 0) {
|
||||||
// Create dropdown options menu, then add it to the DOM then on change, update the regular input.
|
// Create dropdown options menu, then add it to the DOM then on change, update the regular input.
|
||||||
var sshSelect = document.createElement('select');
|
let sshSelect = document.createElement('select');
|
||||||
sshSelect.className = 'form-control';
|
sshSelect.className = 'form-control';
|
||||||
|
|
||||||
sshKeys.forEach(function(sshkey) {
|
sshKeys.forEach(function(sshkey) {
|
||||||
var option = document.createElement('option');
|
let option = document.createElement('option');
|
||||||
option.value = sshkey.id;
|
option.value = sshkey.id;
|
||||||
option.text = sshkey.name;
|
option.text = sshkey.name;
|
||||||
sshSelect.appendChild(option);
|
sshSelect.appendChild(option);
|
||||||
@@ -116,8 +118,9 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
|
|||||||
sshInputField.style.display = 'none';
|
sshInputField.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
sshInputField.style.display = 'none';
|
sshInputField.style.display = 'none';
|
||||||
|
sshInputLabel.style.display = 'none';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
";
|
";
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ModuleFunctions extends Module
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$server = $params['serverid'] ?: false;
|
$server = $params['serverid'] ?: false;
|
||||||
$cp = $this->getCP($server, $server ? false : true);
|
$cp = $this->getCP($server, !$server);
|
||||||
|
|
||||||
if (!$cp) {
|
if (!$cp) {
|
||||||
return 'No Control server found.';
|
return 'No Control server found.';
|
||||||
@@ -82,7 +82,7 @@ class ModuleFunctions extends Module
|
|||||||
[
|
[
|
||||||
"name" => $user->firstname . ' ' . $user->lastname,
|
"name" => $user->firstname . ' ' . $user->lastname,
|
||||||
"email" => $user->email,
|
"email" => $user->email,
|
||||||
"extRelationId" => $user->id
|
"extRelationId" => $user->id,
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -96,7 +96,6 @@ class ModuleFunctions extends Module
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 'Error processing user account.';
|
return 'Error processing user account.';
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode($data);
|
$data = json_decode($data);
|
||||||
@@ -192,7 +191,9 @@ class ModuleFunctions extends Module
|
|||||||
* Allows changing of the package of a server
|
* Allows changing of the package of a server
|
||||||
*
|
*
|
||||||
* @author https://github.com/BlinkohHost/virtfusion-whmcs-module
|
* @author https://github.com/BlinkohHost/virtfusion-whmcs-module
|
||||||
|
*
|
||||||
* @param $params
|
* @param $params
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function changePackage($params)
|
public function changePackage($params)
|
||||||
@@ -218,6 +219,7 @@ class ModuleFunctions extends Module
|
|||||||
if (property_exists($data, 'msg')) {
|
if (property_exists($data, 'msg')) {
|
||||||
return $data->msg;
|
return $data->msg;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return 'Update package request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
return 'Update package request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
||||||
}
|
}
|
||||||
@@ -256,7 +258,6 @@ class ModuleFunctions extends Module
|
|||||||
Database::deleteSystemService($params['serviceid']);
|
Database::deleteSystemService($params['serviceid']);
|
||||||
$this->updateWhmcsServiceParamsOnDestroy($params['serviceid']);
|
$this->updateWhmcsServiceParamsOnDestroy($params['serviceid']);
|
||||||
return 'success';
|
return 'success';
|
||||||
break;
|
|
||||||
|
|
||||||
case 404:
|
case 404:
|
||||||
if (property_exists($data, 'msg')) {
|
if (property_exists($data, 'msg')) {
|
||||||
@@ -269,11 +270,9 @@ class ModuleFunctions extends Module
|
|||||||
} else {
|
} else {
|
||||||
return '404 was returned from the web service without the msg property. The service may be currently unavailable.';
|
return '404 was returned from the web service without the msg property. The service may be currently unavailable.';
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 'Termination request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
return 'Termination request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'Service not found. Termination routine has already been run?';
|
return 'Service not found. Termination routine has already been run?';
|
||||||
@@ -307,7 +306,6 @@ class ModuleFunctions extends Module
|
|||||||
|
|
||||||
case 204:
|
case 204:
|
||||||
return 'success';
|
return 'success';
|
||||||
break;
|
|
||||||
|
|
||||||
case 404:
|
case 404:
|
||||||
if (property_exists($data, 'msg')) {
|
if (property_exists($data, 'msg')) {
|
||||||
@@ -321,7 +319,6 @@ class ModuleFunctions extends Module
|
|||||||
} else {
|
} else {
|
||||||
return '404 was returned from the web service without the msg property. The service may be currently unavailable.';
|
return '404 was returned from the web service without the msg property. The service may be currently unavailable.';
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 423:
|
case 423:
|
||||||
if (property_exists($data, 'msg')) {
|
if (property_exists($data, 'msg')) {
|
||||||
return $data->msg;
|
return $data->msg;
|
||||||
@@ -329,7 +326,6 @@ class ModuleFunctions extends Module
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
return 'Suspend request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
return 'Suspend request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'Service not found.';
|
return 'Service not found.';
|
||||||
@@ -358,10 +354,8 @@ class ModuleFunctions extends Module
|
|||||||
$this->updateWhmcsServiceParamsOnServerObject($params['serviceid'], $data);
|
$this->updateWhmcsServiceParamsOnServerObject($params['serviceid'], $data);
|
||||||
|
|
||||||
return 'success';
|
return 'success';
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return 'Request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
return 'Request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'Service not found.';
|
return 'Service not found.';
|
||||||
@@ -386,7 +380,6 @@ class ModuleFunctions extends Module
|
|||||||
|
|
||||||
case 204:
|
case 204:
|
||||||
return 'success';
|
return 'success';
|
||||||
break;
|
|
||||||
|
|
||||||
case 404:
|
case 404:
|
||||||
if (property_exists($data, 'msg')) {
|
if (property_exists($data, 'msg')) {
|
||||||
@@ -399,15 +392,14 @@ class ModuleFunctions extends Module
|
|||||||
} else {
|
} else {
|
||||||
return '404 was returned from the web service without the msg property. The service may be currently unavailable.';
|
return '404 was returned from the web service without the msg property. The service may be currently unavailable.';
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 423:
|
case 423:
|
||||||
if (property_exists($data, 'msg')) {
|
if (property_exists($data, 'msg')) {
|
||||||
return $data->msg;
|
return $data->msg;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 'Unsuspend request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
return 'Unsuspend request failed. The web service reported HTTP code ' . $request->getRequestInfo('http_code');
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'Service not found';
|
return 'Service not found';
|
||||||
|
|||||||
Reference in New Issue
Block a user