(function (WH)()

in src/main/resources/buildServerResources/gh-webhook.js [4:567]


(function (WH) {
    WH.info = {};
    WH.data = {};
    WH.forcePopup = {};

    WH.SIGN_IN_BUTTON_TITLE = "Sign in to GitHub";
    WH.INSTALL_BUTTON_TITLE = "Install webhook";
    WH.WEBHOOKS_CONTROLLER_PATH = "/oauth/github/webhooks/webhooks.html";

    function onActionSuccessBasic(json, result) {
        var info = json['info'];
        var message = json['message'];
        var repo = info['owner'] + '/' + info['name'];
        var server = info['server'];
        var error = false;
        if ("NotFound" == result) {
            error = true;
        } else if ("TokenScopeMismatch" == result) {
            message = "Token scope does not allow to install webhook to the repository '" + repo + "'";
            error = true;
            // TODO: Add link to refresh/request token (via popup window)
            WH.forcePopup[server] = true
        } else if ("NoAccess" == result) {
            error = true;
        } else if ("Moved" == result) {
            error = true;
        } else if ("InternalServerError" == result) {
        } else if ("UserHaveNoAccess" == result) {
            error = true;
        } else if ("NoOAuthConnections" == result) {
            // TODO: Add link to configure connections, good UI.
            error = true;
        } else if ("Error" == result) {
            error = true;
        } else {
            BS.Log.error("Unexpected result: " + result);
            error = true;
        }

        if (error) {
            WH.showError(message);
        } else {
            WH.showSuccessMessage(message);
        }
    }

    function onActionSuccess(json, result, good) {
        var info = json['info'];
        var message = json['message'];
        var server = info['server'];
        if (good.indexOf(result) > -1) {
            // Good one
            const data = json['data'];
            if (data !== undefined) {
                var repository = data['repository'];
                WH.data[repository] = data;
                renderOne(data, $j('#webHooksTable'))
            }
            WH.showSuccessMessage(message);
            return
        }
        onActionSuccessBasic(json, result);
    }

    var BaseAction = {
        doHandleRedirect: function (json, id, element) {
            WH.forcePopup[WH.getServerUrl(id)] = true;
            var actionId = this.id;
            var text = "Refresh access token and " + this.name + " webhook";

            var link = "<a href='#' onclick=\"return BS.GitHubWebHooks.doAction('" + actionId + "', this)\">" + text + "</a>";

            BS.Util.Messages.hide({group: 'gh_wh_install'});
            BS.Util.Messages.show(id, 'GitHub authorization needed. ' + link);
            $j(element).append(link);
            $(element).onclick = function () {
                return WH.doAction(actionId, element);
            };
            $j(element).html(text);
        },
        doShowProgress: function (element) {
            BS.ProgressPopup.showProgress(element, this.progress, {shift: {x: -65, y: 20}, zIndex: 100});
        },
        doHideProgress: function () {
            BS.ProgressPopup.hidePopup(0, true);
        }
    };

    WH.actions = {
        add: OO.extend(BaseAction, {
            id: "add",
            name: "Add",
            progress: "Adding Webhook",
            doHandleResult: function (json, result) {
                onActionSuccess(json, result, ["AlreadyExists", "Created"]);
            }
        }),
        check: OO.extend(BaseAction, {
            id: "check",
            name: "Check",
            progress: "Checking Webhook",
            doHandleResult: function (json, result) {
                onActionSuccess(json, result, ["Ok"]);
            }
        }),
        ping: OO.extend(BaseAction, {
            id: "ping",
            name: "Resend 'push' payload",
            progress: "Asking GitHub to send push event",
            doHandleResult: function (json, result) {
                onActionSuccess(json, result, ["Ok"]);
            }
        }),
        delete: OO.extend(BaseAction, {
            id: "delete",
            name: "Delete",
            progress: "Deleting Webhook",
            doHandleResult: function (json, result) {
                onActionSuccess(json, result, ["Removed", "NeverExisted"]);
            }
        }),
        install: OO.extend(BaseAction, {
            "id": "install",
            name: "Install",
            progress: "Installing Webhook",
            doHandleResult: function (json, result) {
                this.doHideProgress();
                var good = ["AlreadyExists", "Created"];
                var info = json['info'];
                var message = json['message'];
                var repo = info['owner'] + '/' + info['name'];
                var server = info['server'];

                if (good.indexOf(result) > -1) {
                    // Good one
                    const data = json['data'];
                    if (data !== undefined) {
                        var repository = data['repository'];
                        WH.data[repository] = data;
                    }
                    WH.forcePopup[server] = false;
                    $j("#installWebhookSubmit").attr("value", WH.INSTALL_BUTTON_TITLE);
                    WH.showSuccessMessage(message);
                    return
                }
                if ("TokenScopeMismatch" == result) {
                    message = "Token scope does not allow to install webhook to the repository '" + repo + "'";
                    $j("#installWebhookSubmit").attr("value", WH.SIGN_IN_BUTTON_TITLE);
                    WH.forcePopup[server] = true;
                    WH.showError(message);
                    return
                }
                onActionSuccessBasic(json, result);
            },
            doHandleRedirect: function (json, id) {
                WH.forcePopup[WH.getServerUrl(id)] = true;

                $j("#installWebhookSubmit").attr("value", WH.SIGN_IN_BUTTON_TITLE);
                WH.showError("Please sign in to GitHub to proceed.");
            },
            doHandleError: function (json) {
                this.doHideProgress();
                var error = json['error'];
                WH.showError(error);
            },
            doShowProgress: function () {
                BS.Util.show('installProgress');
                $j('#installButton').attr('disabled', true);
            },
            doHideProgress: function () {
                BS.Util.hide('installProgress');
                $j('#installButton').removeAttr('disabled', false)
            }
        })
    };

    function isSameServer(first, second) {
        if (!first || !second) return false;
        return first.indexOf(second) > -1
    }

    WH.doWebHookAction = function (action, element, id, popup, projectId) {
        // Enforce popup for server if needed
        var server = undefined;
        var info = WH.info[id];
        if (info) {
            server = info['server'];
        } else {
            server = WH.getServerUrl(id);
        }
        if (server && WH.forcePopup[server]) {
            popup = true
        }

        if (popup) {
            var url = BS.ServerInfo.url + WH.WEBHOOKS_CONTROLLER_PATH + '?action=' + action.id + '&popup=true&id=' + id;
            if (projectId !== undefined) {
                url = url + "&projectId=" + projectId
            }
            var popupWin = BS.Util.popupWindow(url, 'webhook_' + action.id + '_' + id);
            var interval = window.setInterval(function() {
              try {
                if (popupWin == null || popupWin.closed) {
                  window.clearInterval(interval);
                  $j("#installWebhookSubmit").attr("value", WH.INSTALL_BUTTON_TITLE);
                  WH.forcePopup[server] = false;
                  WH.doInstallForm($('installWebhookSubmit'));
                }
              } catch (e) {
              }
            }, 1000);
            return;
        }

        var that = element;

        action.doShowProgress(element);

        var parameters = {
            "action": action.id,
            "id": id,
            "popup": popup
        };
        if (projectId !== undefined) {
            parameters["projectId"] = projectId
        }
        var data_holder = $j(element).parents("[data-connection-id]");
        if (data_holder) {
            var conn_server = data_holder.attr('data-connection-server');
            if (isSameServer(server, conn_server)) {
                parameters["connectionId"] = data_holder.attr('data-connection-id');
                parameters["connectionProjectId"] = data_holder.attr('data-connection-project-id');
            }
        }
        //noinspection JSUnusedGlobalSymbols
        BS.ajaxRequest(window.base_uri + WH.WEBHOOKS_CONTROLLER_PATH, {
            method: "post",
            parameters: parameters,
            onComplete: function (transport) {
                var json = transport.responseJSON;
                var action = WH.actions[json['action']] || action;

                action.doHideProgress();

                if (json['redirect']) {
                    BS.Log.info("Redirect response received");
                    action.doHandleRedirect(json, id, that)
                } else {
                    WH.doHandle(json, action)
                }
                WH.refreshReports();
            }
        });
    };

    WH.doHandle = function (json, action) {
        if (json['error']) {
            if (action && action.doHandleError) {
                action.doHandleError(json)
            } else {
                BS.Log.error("Something went wrong: " + json['error']);
                WH.showError(json['error']);
            }
        } else if (json['result']) {
            var res = json['result'];
            if (action) {
                return action.doHandleResult(json, res)
            }
            BS.Log.warn("Unknown action: " + json['action']);
        } else {
            BS.Log.error("Unexpected response: " + JSON.stringify(json))
        }
    };

    WH.refreshReports = function () {
        var summary = $('reportSummary');
        var categories = $('reportCategories');
        if (summary) {
            summary.refresh();
            categories.refresh();
            return
        }
        var popup = $j('.healthItemIndicator[data-popup]');
        if (popup) {
            BS.Hider.hideDiv(popup.attr('data-popup'));
        }
        //window.location.reload(false)
    };

    WH.getServerUrl = function (repository) {
        var s = String(repository);
        return s.substring(0, s.lastIndexOf("/", s.lastIndexOf("/") - 1));
    };

    WH.doAction = function (name, element, repository, projectId, popup) {
        var action = WH.actions[name.toLowerCase()];
        if (!action) {
            BS.Log.error("Unknown action: " + name);
            return false;
        }
        var p;
        if (repository === undefined) {
            var data_holder = $j(element).parents("[data-repository]");
            repository = data_holder.attr('data-repository');
            projectId = data_holder.attr('data-project-id');
        }
        if (popup === undefined) {
            var server = WH.getServerUrl(repository);
            if (!server) {
                // Seems input is incorrect, do not show popup
                p = false;
            } else {
                var fp = WH.forcePopup[server];
                if (fp === undefined) fp = false;
                p = fp;
            }
        } else {
            p = popup
        }
        WH.doWebHookAction(action, element, repository, p, projectId);
        return false;
    };
    WH.checkAll = function (element, projectId, recursive) {
        if (recursive === undefined) recursive = false;
        var parameters = {
            'action': 'check-all',
            'recursive': recursive
        };
        if (projectId) {
            parameters["projectId"] = projectId
        }
        BS.ProgressPopup.showProgress(element, "Rechecking all webhooks", {shift: {x: -65, y: 20}, zIndex: 100});
        BS.ajaxRequest(window.base_uri + WH.WEBHOOKS_CONTROLLER_PATH, {
            method: "post",
            parameters: parameters,
            onComplete: function (transport) {
                BS.ProgressPopup.hidePopup(0, true);
                if (transport.status != 200) {
                    BS.Log.error("Check all responded with " + transport.status);
                    return
                }
                var json = transport.responseJSON;
                if (json['error']) {
                    BS.Log.error("Sad :( Something went wrong: " + json['error']);
                } else if (json['data']) {
                    const table = $j('#webHooksTable');
                    var data = json['data'];
                    for (var i = 0; i < data.length; i++) {
                        var r = data[i];
                        const repo = r['repository'];
                        WH.data[repo] = r;
                        if (r['user_action_required']) {
                            WH.data[repo].warning = r['error'];
                            WH.forcePopup[getServerUrl(repo)] = true;
                            BS.Log.info("Some user action required to check '" + repo + "' repository.");
                            // TODO: Add link to manually check webhook (popup required)
                            // TODO: Prevent automatic updates, that would hide error (if any)
                            WH.data[repo] = r;
                            WH.data[repo]['manual'] = true;
                            WH.forcePopup[WH.getServerUrl(repo)] = true;
                        } else if (r['result']) {
                            // Operation succeed or failed, at least there's some connections/tokens
                            BS.Log.info("Action either succeed of failed for '" + repo + "'.");
                            WH.data[repo] = r;
                            // TODO: Prevent automatic updates, that would hide error (if any)
                            WH.data[repo]['manual'] = true;
                            // TODO: Do something
                        } else {
                            BS.Log.warn("Action done nothing to '" + repo + "'. Most probably there not connection for that server.");
                            // TODO: Do something
                        }
                        renderOne(r, table)
                    }
                    // TODO: Incremental update
                } else {
                    BS.Log.error("Unexpected response: " + json.toString())
                }
                WH.refreshReports();
            }
        })
    };

    function getStatusClass(status) {
        switch (status) {
            case "NO_INFO":
                return "no-info";
            case "NOT_FOUND":
                return "not-found";
            case "OK":
                return "good";
            case "WAITING_FOR_SERVER_RESPONSE":
                return "pending";
            case "INCORRECT":
                return "error";
            default:
                return "";
        }
    }

    function getStatusPresentation(status) {
        switch (status) {
            case "NO_INFO":
                return "No information";
            case "NOT_FOUND":
                return "Not found";
            case "OK":
                return "OK";
            case "WAITING_FOR_SERVER_RESPONSE":
                return "Waiting for ping event";
            case "INCORRECT":
                return "Incorrect";
            default:
                return status;
        }
    }

    function getStatusDiv(status, error) {
        if (error !== undefined) {
            return '<div class="webhook-status err" data-status="error">Error <a href="#" onclick="BS.GitHubWebHooks.more(this); return false">details</a></div>' +
                '<div style="display: none">' + error + '</div>'
        }
        return '<div class="webhook-status ' + getStatusClass(status) + '" data-status="' + status + '">' + getStatusPresentation(status) + '</div>'
    }

    function getLinkHtml(repository, hook) {
        if (hook == null) return "";
        return '<a href="//' + repository + '/settings/hooks/' + hook['id'] + '">View on GitHub</a>';
    }

    function getActionsHtml(actions) {
        return actions.map(function (action) {
            return '<div><a href="#" onclick="BS.GitHubWebHooks.doAction(\'' + action + '\', this); return false;">' + action + '</a></div>'
        }).join("");
    }

    function renderOne(data, table) {
        var repository = data['repository']; // string

        var line = $j(table).find("tr[data-repository='" + repository + "']");
        if (line.length == 0) {
            BS.Log.warn("Line not found for repository " + repository);
            return;
        }

        var error = data['error']; // String?
        var info = data['info']; // VcsRootGitHubInfo?
        var hook = data['hook']; // HookInfo?
        var status = data['status']; // String?
        var actions = data['actions']; // List<String>?
        var warning = data['warning']; // boolean?
        line.find("[data-view=status]").html(getStatusDiv(status, error));
        line.find("[data-view=actions]").html(getActionsHtml(actions));
        line.find("[data-view=link]").html(getLinkHtml(repository, hook));
    }

    WH.refresh = function (element, repositories, table, projectId) {
        if (repositories === undefined) {
            if (table !== undefined) {
                var data_holders = $j(table).find("[data-repository]");
                repositories = data_holders.map(function () {
                    return $j(this).attr('data-repository');
                }).toArray();
            } else if (element !== undefined) {
                var data_holder = $j(element).parents("[data-repository]");
                repositories = [data_holder.attr('data-repository')];
            } else return;
        }
        if (repositories.length < 1) return;
        if (table === undefined) {
            table = $j('#webHooksTable');
        }
        if (element !== undefined) {
            BS.ProgressPopup.showProgress(element, "Refreshing webhook" + (repositories.length > 1 ? 's' : ''), {shift: {x: -65, y: 20}, zIndex: 100});
        } else if (table !== undefined) {
            $j(table).find('.spinner').show();
        }
        BS.ajaxRequest(window.base_uri + WH.WEBHOOKS_CONTROLLER_PATH, {
            method: 'post',
            parameters: {
                'action': 'get-info',
                'projectId': projectId,
                'repository': repositories
            },
            onComplete: function (transport) {
                if (element !== undefined) {
                    BS.ProgressPopup.hidePopup(0, true);
                } else if (table !== undefined) {
                    $j(table).find('.spinner').hide();
                }
                if (transport.status != 200) {
                    BS.Log.error("Fetching webhooks info responded with " + transport.status);
                    return
                }
                var json = transport.responseJSON;
                if (json['error']) {
                    BS.Log.error("Sad :( Something went wrong: " + json['error']);
                } else if (json['result']) {
                    var arr = json['result'];
                    // Update internal data structure, then re-render table
                    for (var i = 0; i < arr.length; i++) {
                        var r = arr[i];
                        var repository = r['repository'];
                        if (WH.data[repository] && WH.data[repository]['manual']) {
                            if (!element) {
                                continue
                            }
                            WH.data[repository]['manual'] = false;
                        }
                        WH.data[repository] = r;
                    }
                    WH.renderTable($j(table));
                } else {
                    BS.Log.error("Unexpected response: " + json.toString())
                }
                WH.refreshReports();
            }
        })
    };

    WH.refreshTable = function (table, projectId) {
        WH.refresh(undefined, undefined, table, projectId)
    };

    WH.renderTable = function (table) {
        for (var k in WH.data) {
            if (!WH.data.hasOwnProperty(k)) continue;
            renderOne(WH.data[k], table);
        }
    };

    WH.more = function (element) {
        const text = $j(element).parent().next().text();
        BS.WarningPopup.showWarning(element, {x: -65, y: 20}, text);
    };

    WH.doInstallForm = function (element) {
        var repository = $j('input#repository').val();
        var projectId = $j('input#projectId').val();

        this.clearMessages();

        if (!repository || repository.length == 0) {
            this.showError("Repository URL is not specified");
            return false;
        }

        return WH.doAction('install', element, repository, projectId);
    };

    WH.showError = function(text) {
        WH.clearMessages();
        $j('#webhookError').html(text).show();
    };

    WH.showSuccessMessage = function(text) {
        WH.clearMessages();
        $j('#webhookMessage').html(text).show();
    };

    WH.clearMessages = function() {
        $j('.error').text("").hide();
        $j('#webhookMessage').text("").hide();
    };
})(BS.GitHubWebHooks);