front end interface for adding/removing/listing subdomains for accounts is in place

This commit is contained in:
George Shaw 2018-01-23 15:35:48 -06:00
parent d57cb9afa3
commit f802fd8eac
10 changed files with 331 additions and 2 deletions

View file

@ -0,0 +1,30 @@
jQuery('._js_add-subdomain-form').on('submit', function(e){
e.preventDefault();
if(jQuery('#addSubdomain') && jQuery('#addSubdomain').val() && jQuery('#subdomainRoot') && jQuery('#subdomainRoot').val()) {
var requestData = {};
requestData["name"] = jQuery('#addSubdomain').val();
requestData["root"] = jQuery('#subdomainRoot').val();
var xhr = new XMLHttpRequest();
xhr.open(jQuery(this).attr('method'), jQuery(this).attr('action'), true);
xhr.send(JSON.stringify(requestData));
xhr.onloadend = function() {
if(xhr.status == 204) {
ListSubdomains();
}
else {
if(xhr.response != undefined && xhr.response.length != 0) {
alert('Error: ' + xhr.status);
}
else {
alert('An error has occurred. If problem persists please contact your community administrator.');
}
}
}
}
else {
alert('All fields must be filled out to submit this form.');
}
});

View file

@ -0,0 +1,37 @@
var subdomainModal = jQuery('.subdomain-management-modal');
jQuery('._js_subdomain-management').on('click', function(e){
e.preventDefault();
ListSubdomains();
subdomainModal.modal('show');
});
function ListSubdomains() {
var list = jQuery('._js_registered-subdomains');
var xhr = new XMLHttpRequest();
xhr.open('GET', 'api/subdomain/list', true);
xhr.send();
xhr.onloadend = function() {
list.html('');
if(xhr.status == 200) {
jsonResponse = JSON.parse(xhr.response)
jQuery.each(jsonResponse, function(k, v) {
list.append('<div class="row mt-2"><div class="col-6"><p class="mb-0">'+k+'</p><small>Root: '+v.root+'</small></div><div class="col-6 d-flex justify-content-end"><div class="btn-group" role="group"><button class="btn btn-outline-danger _js_delete-registered-subdomain" data="'+k+'">Delete</button></div></div></div>');
});
}
else if(xhr.status == 204) {
list.html('<div class="row mt-2"><div class="col-6 d-flex align-items-center"><p>No registered subdomains exist for this account.</p></div></div>');
}
else {
if(xhr.response != undefined && xhr.response.length != 0) {
alert('Error: ' + xhr.status);
}
else {
alert('An error has occurred. If problem persists please contact your community administrator.');
}
}
}
}

View file

@ -0,0 +1,29 @@
jQuery(document).on('click', '._js_delete-registered-subdomain', function(e){
e.preventDefault();
var subdomain = jQuery(this).attr('data');
var ensure = confirm("Are you sure you want to delete the subdomain \""+ subdomain +"\" from your account?");
if(ensure) {
var requestData = {};
requestData["name"] = subdomain;
var xhr = new XMLHttpRequest();
xhr.open('DELETE', 'api/subdomain/remove', true);
xhr.send(JSON.stringify(requestData));
xhr.onloadend = function () {
if (xhr.status == 204) {
ListSubdomains();
}
else {
if (xhr.response != undefined && xhr.response.length != 0) {
alert('Error: ' + xhr.status);
}
else {
alert('An error has occurred. If problem persists please contact your community administrator.');
}
}
}
}
});

View file

@ -349,6 +349,48 @@
</div>
</div>
<!-- Sub-domain Management Modal -->
<div class="modal fade subdomain-management-modal" tabindex="-1" role="dialog" aria-labelledby="subdomain-management-modal" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Sub-domain Management</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h4>Add Sub-domain</h4>
<form method="POST" action="api/subdomain/add" class="_js_add-subdomain-form">
<div class="form-group">
<label for="addSubdomain" class="">Sub-domain</label>
<div class="input-group">
<input type="text" id="addSubdomain" class="form-control" placeholder="Sub-domain">
</div>
</div>
<div class="form-group">
<label for="subdomainRoot" class="">Sub-domain Root</label>
<div class="input-group">
<input type="text" id="subdomainRoot" aria-describedby="subdomainRootHelp" class="form-control" placeholder="Sub-domain Root">
</div>
<small id="subdomainRootHelp" class="form-text text-muted">A directory within your /home/document_root/ to serve as the root for this sub-domain</small>
</div>
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary">Add Sub-domain</button>
</div>
</form>
<h4 class="mt-3 mb-0">Registered Sub-domains</h4>
<div class="container-full _js_registered-subdomains">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-12">
@ -447,6 +489,7 @@
<h6 class="card-subtitle mb-4 text-muted">View registered domains, register new domains, and set up or manage existing document roots for sub-domains.</h6>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-primary _js_domain-management">Domain Management</button>
<button type="button" class="btn btn-outline-primary _js_subdomain-management">Sub-domain Management</button>
</div>
</div>
</div>
@ -501,6 +544,9 @@
<script type="text/javascript" src="assets/js/panelHandlers/domains_subdomains/domain_management.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/domains_subdomains/domain_link.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/domains_subdomains/domain_unlink.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/domains_subdomains/subdomain_management.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/domains_subdomains/subdomain_add.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/domains_subdomains/subdomain_remove.js"></script>
<!-- KEEP AT BOTTOM OF BODY TAGS -->
</body>
</html>

48
pkg/api/subdomain/add.go Normal file
View file

@ -0,0 +1,48 @@
package subdomain
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/Ennovar/gPanel/pkg/database"
)
func Add(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
if req.Method != "POST" {
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return false
}
var requestData struct {
Name string `json:"name"`
Root string `json:"root"`
}
err := json.NewDecoder(req.Body).Decode(&requestData)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusBadRequest)
return false
}
ds, err := database.Open(dir + database.DB_MAIN)
if err != nil || ds == nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
defer ds.Close()
err = ds.Put(database.BUCKET_SUBDOMAINS, []byte(requestData.Name), database.StructSubdomain{Root: requestData.Root})
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
res.WriteHeader(http.StatusNoContent)
return true
}

49
pkg/api/subdomain/list.go Normal file
View file

@ -0,0 +1,49 @@
package subdomain
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/Ennovar/gPanel/pkg/database"
)
func List(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
if req.Method != "GET" {
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return false
}
ds, err := database.Open(dir + database.DB_MAIN)
if err != nil || ds == nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
defer ds.Close()
subdomains, err := ds.ListSubdomains()
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
if len(subdomains) > 0 {
b, err := json.Marshal(subdomains)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
res.WriteHeader(http.StatusOK)
res.Write(b)
return true
}
res.WriteHeader(http.StatusNoContent)
return true
}

View file

@ -0,0 +1,47 @@
package subdomain
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/Ennovar/gPanel/pkg/database"
)
func Remove(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
if req.Method != "DELETE" {
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return false
}
var requestData struct {
Name string `json:"name"`
}
err := json.NewDecoder(req.Body).Decode(&requestData)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusBadRequest)
return false
}
ds, err := database.Open(dir + database.DB_MAIN)
if err != nil || ds == nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
defer ds.Close()
err = ds.Delete(database.BUCKET_SUBDOMAINS, []byte(requestData.Name))
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
res.WriteHeader(http.StatusNoContent)
return true
}

View file

@ -14,7 +14,7 @@ import (
const (
DB_MAIN = "datastore.db"
DB_SETTINGS = "settings.db"
DB_DOMAINS = "domains.db"
DB_DOMAINS = "domains.db"
)
// Bucket constants
@ -23,9 +23,10 @@ const (
BUCKET_USERS = "users"
BUCKET_PORTS = "ports"
BUCKET_FILTERED_IPS = "filtered_ips"
BUCKET_SUBDOMAINS = "subdomains"
// DB_SETTINGS BUCKETS
BUCKET_GENERAL = "general"
BUCKET_GENERAL = "general"
BUCKET_NAMESERVERS = "nameservers"
// DB_DOMAINS BUCKETS
@ -71,6 +72,11 @@ func Open(filepath string) (*Datastore, error) {
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_SUBDOMAINS))
if err != nil {
return err
}
}
if strings.HasSuffix(filepath, DB_SETTINGS) {

View file

@ -0,0 +1,30 @@
package database
import (
"encoding/json"
"github.com/boltdb/bolt"
)
type StructSubdomain struct {
Root string `json:"root"`
}
func (ds *Datastore) ListSubdomains() (map[string]StructSubdomain, error) {
filtered := make(map[string]StructSubdomain)
var holder StructSubdomain
ds.handle.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(BUCKET_SUBDOMAINS))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
json.Unmarshal(v, &holder)
filtered[string(k)] = holder
}
return nil
})
return filtered, nil
}

View file

@ -11,6 +11,7 @@ import (
"github.com/Ennovar/gPanel/pkg/api/server"
"github.com/Ennovar/gPanel/pkg/api/settings"
"github.com/Ennovar/gPanel/pkg/api/ssh"
"github.com/Ennovar/gPanel/pkg/api/subdomain"
"github.com/Ennovar/gPanel/pkg/api/user"
)
@ -74,6 +75,12 @@ func (con *Controller) apiHandler(res http.ResponseWriter, req *http.Request) (b
return true, ssh.DeleteKey(res, req, con.APILogger)
case "/ssh/getkeys":
return true, ssh.GetKeys(res, req, con.APILogger)
case "/subdomain/list":
return true, subdomain.List(res, req, con.APILogger, con.Directory)
case "/subdomain/add":
return true, subdomain.Add(res, req, con.APILogger, con.Directory)
case "/subdomain/remove":
return true, subdomain.Remove(res, req, con.APILogger, con.Directory)
default:
return false, false
}