Skip to content

Commit

Permalink
Merge pull request #478 from jmpsec/api-tags-platforms
Browse files Browse the repository at this point in the history
Adding tags and platforms by environment in osctrl-api
  • Loading branch information
javuto authored Aug 17, 2024
2 parents 64ec887 + 97d55ae commit 47ed750
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 58 deletions.
19 changes: 13 additions & 6 deletions admin/handlers/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ func (h *HandlersAdmin) EnvsPOSTHandler(w http.ResponseWriter, r *http.Request)
return
}
// Create a tag for this new environment
if err := h.Tags.NewTag(env.Name, "Tag for environment "+env.Name, "", env.Icon, ctx[sessions.CtxUser]); err != nil {
if err := h.Tags.NewTag(env.Name, "Tag for environment "+env.Name, "", env.Icon, ctx[sessions.CtxUser], env.ID); err != nil {
adminErrorResponse(w, "error generating tag", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
Expand Down Expand Up @@ -1406,6 +1406,13 @@ func (h *HandlersAdmin) TagsPOSTHandler(w http.ResponseWriter, r *http.Request)
h.Inc(metricAdminErr)
return
}
// Retrieve environment
env, err := h.Envs.Get(t.Environment)
if err != nil {
adminErrorResponse(w, "error getting environment", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
}
switch t.Action {
case "add":
// FIXME password complexity?
Expand All @@ -1415,29 +1422,29 @@ func (h *HandlersAdmin) TagsPOSTHandler(w http.ResponseWriter, r *http.Request)
return
}
// Prepare user to create
if err := h.Tags.NewTag(t.Name, t.Description, t.Color, t.Icon, ctx[sessions.CtxUser]); err != nil {
if err := h.Tags.NewTag(t.Name, t.Description, t.Color, t.Icon, ctx[sessions.CtxUser], env.ID); err != nil {
adminErrorResponse(w, "error with new tag", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
}
adminOKResponse(w, "tag added successfully")
case "edit":
if t.Description != "" {
if err := h.Tags.ChangeDescription(t.Name, t.Description); err != nil {
if err := h.Tags.ChangeDescription(t.Name, t.Description, env.ID); err != nil {
adminErrorResponse(w, "error changing description", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
}
}
if t.Icon != "" {
if err := h.Tags.ChangeIcon(t.Name, t.Icon); err != nil {
if err := h.Tags.ChangeIcon(t.Name, t.Icon, env.ID); err != nil {
adminErrorResponse(w, "error changing icon", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
}
}
if t.Color != "" {
if err := h.Tags.ChangeColor(t.Name, t.Color); err != nil {
if err := h.Tags.ChangeColor(t.Name, t.Color, env.ID); err != nil {
adminErrorResponse(w, "error changing color", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
Expand All @@ -1451,7 +1458,7 @@ func (h *HandlersAdmin) TagsPOSTHandler(w http.ResponseWriter, r *http.Request)
return
}
if h.Tags.Exists(t.Name) {
if err := h.Tags.Delete(t.Name); err != nil {
if err := h.Tags.Delete(t.Name, env.ID); err != nil {
adminErrorResponse(w, "error removing tag", http.StatusInternalServerError, err)
h.Inc(metricAdminErr)
return
Expand Down
5 changes: 3 additions & 2 deletions admin/handlers/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -1459,8 +1459,9 @@ func (h *HandlersAdmin) TagsGETHandler(w http.ResponseWriter, r *http.Request) {
}
// Custom functions to handle formatting
funcMap := template.FuncMap{
"pastFutureTimes": utils.PastFutureTimes,
"inFutureTime": utils.InFutureTime,
"pastFutureTimes": utils.PastFutureTimes,
"inFutureTime": utils.InFutureTime,
"environmentFinder": environments.EnvironmentFinder,
}
// Prepare template
tempateFiles := h.NewTemplateFiles(h.TemplatesFolder, "tags.html").filepaths
Expand Down
1 change: 1 addition & 0 deletions admin/handlers/types-requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ type TagsRequest struct {
Description string `json:"description"`
Color string `json:"color"`
Icon string `json:"icon"`
Environment string `json:"environment"`
}

// TagNodesRequest to receive a tag for nodes
Expand Down
45 changes: 28 additions & 17 deletions admin/static/js/tags.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
function createTag() {
$("#modal_title_tag").text('Create new Tag');
$("#modal_button_tag").text('Create');
$('#modal_button_tag').click(function () {
$('#createEditTagModal').modal('hide');
$("#modal_title_tag").text("Create new Tag");
$("#modal_button_tag").text("Create");
$("#modal_button_tag").click(function () {
$("#createEditTagModal").modal("hide");
confirmCreateTag();
});
generateColor();
$("#tag_name").val("");
$("#tag_description").val("");
$("#tag_icon").val("");
$("#tag_env").val("");
$("#createEditTagModal").modal();
}

function editTag(_name) {
$("#modal_title_tag").text('Edit Tag ' + _name);
$("#modal_button_tag").text('Update');
$('#modal_button_tag').click(function () {
$('#createEditTagModal').modal('hide');
$("#modal_title_tag").text("Edit Tag " + _name);
$("#modal_button_tag").text("Update");
$("#modal_button_tag").click(function () {
$("#createEditTagModal").modal("hide");
confirmEditTag();
});
$("#tag_name").val(_name);
$("#tag_description").val($("#tag_desc_" + _name).val());
$("#tag_color").val($("#tag_color_" + _name).val());
$("#tag_icon").val($("#tag_icon_" + _name).val());
$("#tag_env").val($("#tag_env_" + _name).val());
$("#createEditTagModal").modal();
}

Expand All @@ -30,13 +35,15 @@ function confirmCreateTag() {
var _description = $("#tag_description").val();
var _color = $("#tag_color").val();
var _icon = $("#tag_icon").val();
var _env = $("#tag_env").val();
var data = {
csrftoken: _csrftoken,
action: 'add',
action: "add",
name: _name,
description: _description,
color: _color,
icon: _icon,
environment: _env,
};
sendPostRequest(data, _url, _url, false);
}
Expand All @@ -48,22 +55,24 @@ function confirmEditTag() {
var _description = $("#tag_description").val();
var _color = $("#tag_color").val();
var _icon = $("#tag_icon").val();
var _env = $("#tag_env").val();
var data = {
csrftoken: _csrftoken,
action: 'edit',
action: "edit",
name: _name,
description: _description,
color: _color,
icon: _icon,
environment: _env,
};
sendPostRequest(data, _url, _url, false);
}

function confirmDeleteTag(_tag) {
var modal_message = 'Are you sure you want to delete the tag ' + _tag + '?';
var modal_message = "Are you sure you want to delete the tag " + _tag + "?";
$("#confirmModalMessage").text(modal_message);
$('#confirm_action').click(function () {
$('#confirmModal').modal('hide');
$("#confirm_action").click(function () {
$("#confirmModal").modal("hide");
deleteTag(_tag);
});
$("#confirmModal").modal();
Expand All @@ -72,16 +81,18 @@ function confirmDeleteTag(_tag) {
function deleteTag(_tag) {
var _csrftoken = $("#csrftoken").val();
var _url = window.location.pathname;
var _env = $("#tag_env_" + _tag).val();
var data = {
csrftoken: _csrftoken,
action: 'remove',
action: "remove",
name: _tag,
environment: _env,
};
sendPostRequest(data, _url, _url, false);
}

function generateColor() {
var randomColor = '#' + Math.random().toString(16).substr(2, 6);
$('#tag_color').val(randomColor);
$('#show_color').css('background-color', randomColor);
var randomColor = "#" + Math.random().toString(16).substr(2, 6);
$("#tag_color").val(randomColor);
$("#show_color").css("background-color", randomColor);
}
21 changes: 21 additions & 0 deletions admin/templates/tags.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<th>Description</th>
<th>Color</th>
<th>Icon</th>
<th>Environment</th>
<th></th>
</tr>
</thead>
Expand All @@ -58,6 +59,9 @@
<span style="color: {{ $t.Color }}; background-color: {{ $t.Color }};">##</span>
</td>
<td>{{ $t.Icon }} <i class="{{ $t.Icon }}"></i><input type="hidden" value="{{ $t.Icon }}" id="tag_icon_{{ $t.Name }}"></td>
<td>
<b>{{ environmentFinder $t.EnvironmentID $.Environments }}</b>
<input type="hidden" value="{{ environmentFinder $t.EnvironmentID $.Environments }}" id="tag_env_{{ $t.Name }}"></td>
<td>
<button type="button" class="btn btn-sm btn-ghost-danger" onclick="confirmDeleteTag('{{ $t.Name }}');">
<i class="far fa-trash-alt"></i>
Expand Down Expand Up @@ -111,6 +115,17 @@ <h4 id="modal_title_tag" class="modal-title"></h4>
<input class="form-control" name="tag_icon" id="tag_icon" type="text" value="fas fa-tag">
</div>
</div>
<div class="form-group row">
<label class="col-md-2 col-form-label" for="tag_env">Environment: </label>
<div class="col-md-4">
<select class="form-control" name="tag_env" id="tag_env">
<option value=""></option>
{{ range $i, $e := $.Environments }}
<option value="{{ $e.UUID }}">{{ $e.Name }}</option>
{{ end }}
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button id="modal_button_tag" type="button" class="btn btn-primary" data-dismiss="modal">Create</button>
Expand Down Expand Up @@ -147,6 +162,12 @@ <h4 id="modal_title_tag" class="modal-title"></h4>
$("#tag_show_icon").addClass($('#tag_icon').val());
});

// Select2 initialization
$('#tag_env').select2({
theme: "classic",
width: '100%'
});

// Enable all tooltips
$('[data-tooltip="true"]').tooltip({trigger : 'hover'});

Expand Down
46 changes: 46 additions & 0 deletions api/handlers-platforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"net/http"

"github.com/gorilla/mux"
"github.com/jmpsec/osctrl/settings"
"github.com/jmpsec/osctrl/users"
"github.com/jmpsec/osctrl/utils"
Expand Down Expand Up @@ -41,3 +42,48 @@ func apiPlatformsHandler(w http.ResponseWriter, r *http.Request) {
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, platforms)
incMetric(metricAPIPlatformsOK)
}

// GET Handler to return platforms for one environment as JSON
func apiPlatformsEnvHandler(w http.ResponseWriter, r *http.Request) {
incMetric(metricAPIPlatformsReq)
utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAPI, settings.NoEnvironmentID), false)
vars := mux.Vars(r)
// Extract environment
envVar, ok := vars["env"]
if !ok {
apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil)
incMetric(metricAPIEnvsErr)
return
}
// Get environment by name
env, err := envs.Get(envVar)
if err != nil {
if err.Error() == "record not found" {
apiErrorResponse(w, "environment not found", http.StatusNotFound, err)
} else {
apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, err)
}
incMetric(metricAPIEnvsErr)
return
}
// Get context data and check access
ctx := r.Context().Value(contextKey(contextAPI)).(contextValue)
if !apiUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) {
apiErrorResponse(w, "no access", http.StatusForbidden, fmt.Errorf("attempt to use API by user %s", ctx[ctxUser]))
incMetric(metricAPIPlatformsErr)
return
}
// Get platforms
platforms, err := nodesmgr.GetEnvPlatforms(env.UUID)
if err != nil {
apiErrorResponse(w, "error getting platforms", http.StatusInternalServerError, err)
incMetric(metricAPIPlatformsErr)
return
}
// Serialize and serve JSON
if settingsmgr.DebugService(settings.ServiceAPI) {
log.Println("DebugService: Returned platforms")
}
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, platforms)
incMetric(metricAPIPlatformsOK)
}
46 changes: 46 additions & 0 deletions api/handlers-tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"net/http"

"github.com/gorilla/mux"
"github.com/jmpsec/osctrl/settings"
"github.com/jmpsec/osctrl/users"
"github.com/jmpsec/osctrl/utils"
Expand Down Expand Up @@ -41,3 +42,48 @@ func apiTagsHandler(w http.ResponseWriter, r *http.Request) {
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, tags)
incMetric(metricAPITagsOK)
}

// GET Handler to return tags for one environment as JSON
func apiTagsEnvHandler(w http.ResponseWriter, r *http.Request) {
incMetric(metricAPITagsReq)
utils.DebugHTTPDump(r, settingsmgr.DebugHTTP(settings.ServiceAPI, settings.NoEnvironmentID), false)
vars := mux.Vars(r)
// Extract environment
envVar, ok := vars["env"]
if !ok {
apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil)
incMetric(metricAPIEnvsErr)
return
}
// Get environment by name
env, err := envs.Get(envVar)
if err != nil {
if err.Error() == "record not found" {
apiErrorResponse(w, "environment not found", http.StatusNotFound, err)
} else {
apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, err)
}
incMetric(metricAPIEnvsErr)
return
}
// Get context data and check access
ctx := r.Context().Value(contextKey(contextAPI)).(contextValue)
if !apiUsers.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) {
apiErrorResponse(w, "no access", http.StatusForbidden, fmt.Errorf("attempt to use API by user %s", ctx[ctxUser]))
incMetric(metricAPITagsErr)
return
}
// Get tags
tags, err := tagsmgr.GetByEnv(env.ID)
if err != nil {
apiErrorResponse(w, "error getting tags", http.StatusInternalServerError, err)
incMetric(metricAPITagsErr)
return
}
// Serialize and serve JSON
if settingsmgr.DebugService(settings.ServiceAPI) {
log.Println("DebugService: Returned tags")
}
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, tags)
incMetric(metricAPITagsOK)
}
4 changes: 4 additions & 0 deletions api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ func osctrlAPIService() {
// API: platforms
routerAPI.Handle(_apiPath(apiPlatformsPath), handlerAuthCheck(http.HandlerFunc(apiPlatformsHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiPlatformsPath)+"/", handlerAuthCheck(http.HandlerFunc(apiPlatformsHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiPlatformsPath)+"/{env}", handlerAuthCheck(http.HandlerFunc(apiPlatformsEnvHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiPlatformsPath)+"/{env}/", handlerAuthCheck(http.HandlerFunc(apiPlatformsEnvHandler))).Methods("GET")
// API: environments by environment
routerAPI.Handle(_apiPath(apiEnvironmentsPath)+"/{env}", handlerAuthCheck(http.HandlerFunc(apiEnvironmentHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiEnvironmentsPath)+"/{env}/", handlerAuthCheck(http.HandlerFunc(apiEnvironmentHandler))).Methods("GET")
Expand All @@ -575,6 +577,8 @@ func osctrlAPIService() {
// API: tags
routerAPI.Handle(_apiPath(apiTagsPath), handlerAuthCheck(http.HandlerFunc(apiTagsHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiTagsPath)+"/", handlerAuthCheck(http.HandlerFunc(apiTagsHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiTagsPath)+"/{env}", handlerAuthCheck(http.HandlerFunc(apiTagsEnvHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiTagsPath)+"/{env}/", handlerAuthCheck(http.HandlerFunc(apiTagsEnvHandler))).Methods("GET")
// API: settings by environment
routerAPI.Handle(_apiPath(apiSettingsPath), handlerAuthCheck(http.HandlerFunc(apiSettingsHandler))).Methods("GET")
routerAPI.Handle(_apiPath(apiSettingsPath)+"/", handlerAuthCheck(http.HandlerFunc(apiSettingsHandler))).Methods("GET")
Expand Down
2 changes: 1 addition & 1 deletion cli/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func addEnvironment(c *cli.Context) error {
return err
}
// Create a tag for this new environment
if err := tagsmgr.NewTag(newEnv.Name, "Tag for environment "+newEnv.Name, tags.RandomColor(), newEnv.Icon, appName); err != nil {
if err := tagsmgr.NewTag(newEnv.Name, "Tag for environment "+newEnv.Name, tags.RandomColor(), newEnv.Icon, appName, newEnv.ID); err != nil {
return err
}
// Generate flags
Expand Down
10 changes: 10 additions & 0 deletions environments/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,13 @@ func PackageDownloadURL(env TLSEnvironment, pkg string) string {
}
return fmt.Sprintf("https://%s/%s/%s/package/%s", env.Hostname, env.UUID, env.Secret, pkg)
}

// EnvironmentFinder to find the environment and return its name based on the environment ID
func EnvironmentFinder(envID uint, envs []TLSEnvironment) string {
for _, env := range envs {
if env.ID == envID {
return env.Name
}
}
return "Unknown"
}
Loading

0 comments on commit 47ed750

Please sign in to comment.