<commit_before>/// <reference path="../../../../lib2/types/angular.d.ts"/>
/// <reference path="../../../../lib2/types/lodash.d.ts"/>

import * as _ from "lodash";

import * as AdhBadge from "../Badge/Badge";
import * as AdhConfig from "../Config/Config";
import * as AdhCrossWindowMessaging from "../CrossWindowMessaging/CrossWindowMessaging";
import * as AdhHttp from "../Http/Http";
import * as AdhPermissions from "../Permissions/Permissions";
import * as AdhResourceActions from "../ResourceActions/ResourceActions";
import * as AdhResourceArea from "../ResourceArea/ResourceArea";
import * as AdhTopLevelState from "../TopLevelState/TopLevelState";
import * as AdhEmbed from "../Embed/Embed";
import * as AdhUtil from "../Util/Util";

import * as AdhCredentials from "./Credentials";
import * as AdhUser from "./User";

import * as ResourcesBase from "../../ResourcesBase";

import RIComment from "../../../Resources_/adhocracy_core/resources/comment/IComment";
import RIProposal from "../../../Resources_/adhocracy_core/resources/proposal/IProposal";
import RIRate from "../../../Resources_/adhocracy_core/resources/rate/IRate";
import RIUser from "../../../Resources_/adhocracy_core/resources/principal/IUser";
import RISystemUser from "../../../Resources_/adhocracy_core/resources/principal/ISystemUser";
import * as SIAnonymizeDefault from "../../../Resources_/adhocracy_core/sheets/principal/IAnonymizeDefault";
import * as SIDescription from "../../../Resources_/adhocracy_core/sheets/description/IDescription";
import * as SIEmailNew from "../../../Resources_/adhocracy_core/sheets/principal/IEmailNew";
import * as SIHasAssetPool from "../../../Resources_/adhocracy_core/sheets/asset/IHasAssetPool";
import * as SIImageReference from "../../../Resources_/adhocracy_core/sheets/image/IImageReference";
import * as SIMetadata from "../../../Resources_/adhocracy_core/sheets/metadata/IMetadata";
import * as SIPasswordAuthentication from "../../../Resources_/adhocracy_core/sheets/principal/IPasswordAuthentication";
import * as SIPool from "../../../Resources_/adhocracy_core/sheets/pool/IPool";
import * as SIUserBasic from "../../../Resources_/adhocracy_core/sheets/principal/IUserBasic";

var pkgLocation = "/Core/User";


/**
 * register / password reset flow
 * ------------------------------
 *
 * Register and password reset require that a user reacts to an email.  The flow is
 * initiated by visiting a page.  After that, a mail containing a link is sent to
 * the user.  When the user clicks the link, a new tab is opened in which the flow
 * can be completed.
 *
 * There are several issues related to this flow:
 *
 * -   After the flow is completed, we would like to offer a way back to the
 *     location where it was initiated.  As this information is not dragged along,
 *     we can only save it as `cameFrom` in the initial tab.  If that information
 *     is not available (e.g. because the initial tab has been closed) we fall back
 *     to a fixed location.
 *
 * -   Having two open tabs in the end could confuse users.
 *
 * -   The user might have closed the initial tab in the meantime or react to
 *     the mail on a different device.  If password reset is (mis)used for
 *     inviting new users, that initial tab will never have existed in the first
 *     place.
 *
 * -   If the flow is completed successfully, we would like to notify the initial
 *     tab.  That might be prohibited by security policies (3rd party cookie).
 *
 * -   If `cameFrom` is not available we need to redirect to a fixed location. It
 *     is not clear what this would be if there is no central platform but many
 *     independent embedded instances of adhocracy.
 *
 * -   We could drag along the `cameFrom` information. In that case, we should also
 *     drag along the information on where it was embedded. On the other hand, we
 *     should not pass any sensitive information to the embedding page (e.g.
 *     password reset token).
 *
 * There are basically two options to implement this:
 *
 * -   Prompt the user to close the second tab and continue using the first one.
 *     This way they end up with a single tab that contains the `cameFrom`
 *     information, but are lost if the initial tab does not exist.
 *
 * -   Let the user use the second tab.  They then might have two open tabs and
 *     have lost the `cameFrom` information but are not lost completely.
 *
 * Currently, both options are implemented. The first version is avoided because
 * of the risk of dead ends.  However, if there is no central platform
 * (`custom.embed_only` config) the first version is used.
 */


export interface IScopeLogin extends angular.IScope {
    user : AdhUser.Service;
    loginForm : angular.IFormController;
    credentials : {
        nameOrEmail : string;
        password : <PASSWORD>;
    };
    errors : string[];
    supportEmail : string;

    resetCredentials : () => void;
    enableCancel : boolean;
    cancel : () => void;
    logIn : () => angular.IPromise<void>;
    logInWithServiceKonto : () => void;
    showError;
}


export interface IScopeRegister extends angular.IScope {
    form : {
        register? : angular.IFormController;
    };
    input : {
        username : string;
        email : string;
        password : string;
        passwordRepeat : string;
        captchaGuess : string;
    };
    loggedIn : boolean;
    userName : string;
    siteName : string;
    termsUrl : string;
    captcha : {
        enabled : boolean;
        audioEnabled : boolean;
        toggleAudio : () => void;
        refreshCaptcha : () => void;
        id : string;
        imageData : string;
        audioData : string;
    };
    errors : string[];
    supportEmail : string;
    success : boolean;

    register : () => angular.IPromise<void>;
    enableCancel : boolean;
    cancel : () => void;
    showError;
    logOut : () => void;
    goBack : () => void;
}


var bindServerErrors = (
    $scope : {errors : string[]},
    errors : AdhHttp.IBackendErrorItem[]
) => {
    $scope.errors = [];
    if (!errors.length) {
        $scope.errors.push("Unknown error from server (no details provided)");
    } else {
        errors.forEach((e) => {
            $scope.errors.push(e.description);
        });
    }
};

export var translateUsernameFilter = (
    translateFilter
) => {
    return (userName : string) => {
        if (userName === "anonymous") {
            return translateFilter("TR__ANONYMOUS");
        } else {
            return userName;
        }
    };
};

export var activateArea = (
    adhConfig : AdhConfig.IService,
    adhUser : AdhUser.Service,
    adhDone,
    $scope,
    $location : angular.ILocationService
) : AdhTopLevelState.IAreaInput => {
    $scope.translationData = {
        supportEmail: adhConfig.support_email
    };
    $scope.success = false;
    $scope.ready = false;
    $scope.siteName = adhConfig.site_name;
    $scope.embedOnly = adhConfig.custom["embed_only"] && adhConfig.custom["embed_only"].toLowerCase() === "true";
    $scope.user = adhUser;

    $scope.goBack = () => {
         $location.url("/");
    };

    var key = $location.path().split("/")[2];
    var path = "/activate/" + key;

    adhUser.activate(path)
        .then(() => {
            $scope.success = true;
        })
        .finally(() => {
            $scope.ready = true;
            adhDone();
        });

    return {
        templateUrl: "/static/js/templates/Activation.html"
    };
};


export var loginDirective = (
    adhConfig : AdhConfig.IService,
    adhCrossWindowMessaging : AdhCrossWindowMessaging.IService,
    adhUser : AdhUser.Service,
    adhTopLevelState : AdhTopLevelState.Service,
    adhEmbed : AdhEmbed.Service,
    adhPermissions : AdhPermissions.Service,
    adhShowError,
    $window : angular.IWindowService
) => {
    return {
        restrict: "E",
        templateUrl: adhConfig.pkg_path + pkgLocation + "/Login.html",
        scope: {},
        link: (scope : IScopeLogin) => {
            scope.errors = [];
            scope.supportEmail = adhConfig.support_email;
            scope.showError = adhShowError;

            adhPermissions.bindScope(scope, "/principals/users");

            scope.credentials = {
                nameOrEmail: "",
                password: ""
            };

            scope.resetCredentials = () => {
                scope.credentials.nameOrEmail = "";
                scope.credentials.password = "";
            };

            scope.enableCancel = ! _.includes(["login", "register"], adhEmbed.getContext());

            scope.cancel = () => {
                 adhTopLevelState.goToCameFrom("/");
            };

            var handleErrors = (errors) => {
                bindServerErrors(scope, errors);
                scope.credentials.password = "";
                scope.loginForm.$setPristine();
            };

            scope.logInWithServiceKonto = () => {
                var popup = $window.open(adhConfig.service_konto_login_url, "_blank", "width=460,height=225");

                var cancel = adhCrossWindowMessaging.on("serviceKontoToken", (data) => {
                    adhUser.logInWithServiceKonto(data.token).then(() => {
                        adhTopLevelState.goToCameFrom("/", true);
                    }, handleErrors);

                    popup.close();
                    cancel();
                });
            };

            scope.logIn = () => {<commit_msg>register callack before opening the popup<commit_after>/// <reference path="../../../../lib2/types/angular.d.ts"/>
/// <reference path="../../../../lib2/types/lodash.d.ts"/>

import * as _ from "lodash";

import * as AdhBadge from "../Badge/Badge";
import * as AdhConfig from "../Config/Config";
import * as AdhCrossWindowMessaging from "../CrossWindowMessaging/CrossWindowMessaging";
import * as AdhHttp from "../Http/Http";
import * as AdhPermissions from "../Permissions/Permissions";
import * as AdhResourceActions from "../ResourceActions/ResourceActions";
import * as AdhResourceArea from "../ResourceArea/ResourceArea";
import * as AdhTopLevelState from "../TopLevelState/TopLevelState";
import * as AdhEmbed from "../Embed/Embed";
import * as AdhUtil from "../Util/Util";

import * as AdhCredentials from "./Credentials";
import * as AdhUser from "./User";

import * as ResourcesBase from "../../ResourcesBase";

import RIComment from "../../../Resources_/adhocracy_core/resources/comment/IComment";
import RIProposal from "../../../Resources_/adhocracy_core/resources/proposal/IProposal";
import RIRate from "../../../Resources_/adhocracy_core/resources/rate/IRate";
import RIUser from "../../../Resources_/adhocracy_core/resources/principal/IUser";
import RISystemUser from "../../../Resources_/adhocracy_core/resources/principal/ISystemUser";
import * as SIAnonymizeDefault from "../../../Resources_/adhocracy_core/sheets/principal/IAnonymizeDefault";
import * as SIDescription from "../../../Resources_/adhocracy_core/sheets/description/IDescription";
import * as SIEmailNew from "../../../Resources_/adhocracy_core/sheets/principal/IEmailNew";
import * as SIHasAssetPool from "../../../Resources_/adhocracy_core/sheets/asset/IHasAssetPool";
import * as SIImageReference from "../../../Resources_/adhocracy_core/sheets/image/IImageReference";
import * as SIMetadata from "../../../Resources_/adhocracy_core/sheets/metadata/IMetadata";
import * as SIPasswordAuthentication from "../../../Resources_/adhocracy_core/sheets/principal/IPasswordAuthentication";
import * as SIPool from "../../../Resources_/adhocracy_core/sheets/pool/IPool";
import * as SIUserBasic from "../../../Resources_/adhocracy_core/sheets/principal/IUserBasic";

var pkgLocation = "/Core/User";


/**
 * register / password reset flow
 * ------------------------------
 *
 * Register and password reset require that a user reacts to an email.  The flow is
 * initiated by visiting a page.  After that, a mail containing a link is sent to
 * the user.  When the user clicks the link, a new tab is opened in which the flow
 * can be completed.
 *
 * There are several issues related to this flow:
 *
 * -   After the flow is completed, we would like to offer a way back to the
 *     location where it was initiated.  As this information is not dragged along,
 *     we can only save it as `cameFrom` in the initial tab.  If that information
 *     is not available (e.g. because the initial tab has been closed) we fall back
 *     to a fixed location.
 *
 * -   Having two open tabs in the end could confuse users.
 *
 * -   The user might have closed the initial tab in the meantime or react to
 *     the mail on a different device.  If password reset is (mis)used for
 *     inviting new users, that initial tab will never have existed in the first
 *     place.
 *
 * -   If the flow is completed successfully, we would like to notify the initial
 *     tab.  That might be prohibited by security policies (3rd party cookie).
 *
 * -   If `cameFrom` is not available we need to redirect to a fixed location. It
 *     is not clear what this would be if there is no central platform but many
 *     independent embedded instances of adhocracy.
 *
 * -   We could drag along the `cameFrom` information. In that case, we should also
 *     drag along the information on where it was embedded. On the other hand, we
 *     should not pass any sensitive information to the embedding page (e.g.
 *     password reset token).
 *
 * There are basically two options to implement this:
 *
 * -   Prompt the user to close the second tab and continue using the first one.
 *     This way they end up with a single tab that contains the `cameFrom`
 *     information, but are lost if the initial tab does not exist.
 *
 * -   Let the user use the second tab.  They then might have two open tabs and
 *     have lost the `cameFrom` information but are not lost completely.
 *
 * Currently, both options are implemented. The first version is avoided because
 * of the risk of dead ends.  However, if there is no central platform
 * (`custom.embed_only` config) the first version is used.
 */


export interface IScopeLogin extends angular.IScope {
    user : AdhUser.Service;
    loginForm : angular.IFormController;
    credentials : {
        nameOrEmail : string;
        password : string;
    };
    errors : string[];
    supportEmail : string;

    resetCredentials : () => void;
    enableCancel : boolean;
    cancel : () => void;
    logIn : () => angular.IPromise<void>;
    logInWithServiceKonto : () => void;
    showError;
}


export interface IScopeRegister extends angular.IScope {
    form : {
        register? : angular.IFormController;
    };
    input : {
        username : string;
        email : string;
        password : string;
        passwordRepeat : string;
        captchaGuess : string;
    };
    loggedIn : boolean;
    userName : string;
    siteName : string;
    termsUrl : string;
    captcha : {
        enabled : boolean;
        audioEnabled : boolean;
        toggleAudio : () => void;
        refreshCaptcha : () => void;
        id : string;
        imageData : string;
        audioData : string;
    };
    errors : string[];
    supportEmail : string;
    success : boolean;

    register : () => angular.IPromise<void>;
    enableCancel : boolean;
    cancel : () => void;
    showError;
    logOut : () => void;
    goBack : () => void;
}


var bindServerErrors = (
    $scope : {errors : string[]},
    errors : AdhHttp.IBackendErrorItem[]
) => {
    $scope.errors = [];
    if (!errors.length) {
        $scope.errors.push("Unknown error from server (no details provided)");
    } else {
        errors.forEach((e) => {
            $scope.errors.push(e.description);
        });
    }
};

export var translateUsernameFilter = (
    translateFilter
) => {
    return (userName : string) => {
        if (userName === "anonymous") {
            return translateFilter("TR__ANONYMOUS");
        } else {
            return userName;
        }
    };
};

export var activateArea = (
    adhConfig : AdhConfig.IService,
    adhUser : AdhUser.Service,
    adhDone,
    $scope,
    $location : angular.ILocationService
) : AdhTopLevelState.IAreaInput => {
    $scope.translationData = {
        supportEmail: adhConfig.support_email
    };
    $scope.success = false;
    $scope.ready = false;
    $scope.siteName = adhConfig.site_name;
    $scope.embedOnly = adhConfig.custom["embed_only"] && adhConfig.custom["embed_only"].toLowerCase() === "true";
    $scope.user = adhUser;

    $scope.goBack = () => {
         $location.url("/");
    };

    var key = $location.path().split("/")[2];
    var path = "/activate/" + key;

    adhUser.activate(path)
        .then(() => {
            $scope.success = true;
        })
        .finally(() => {
            $scope.ready = true;
            adhDone();
        });

    return {
        templateUrl: "/static/js/templates/Activation.html"
    };
};


export var loginDirective = (
    adhConfig : AdhConfig.IService,
    adhCrossWindowMessaging : AdhCrossWindowMessaging.IService,
    adhUser : AdhUser.Service,
    adhTopLevelState : AdhTopLevelState.Service,
    adhEmbed : AdhEmbed.Service,
    adhPermissions : AdhPermissions.Service,
    adhShowError,
    $window : angular.IWindowService
) => {
    return {
        restrict: "E",
        templateUrl: adhConfig.pkg_path + pkgLocation + "/Login.html",
        scope: {},
        link: (scope : IScopeLogin) => {
            scope.errors = [];
            scope.supportEmail = adhConfig.support_email;
            scope.showError = adhShowError;

            adhPermissions.bindScope(scope, "/principals/users");

            scope.credentials = {
                nameOrEmail: "",
                password: ""
            };

            scope.resetCredentials = () => {
                scope.credentials.nameOrEmail = "";
                scope.credentials.password = "";
            };

            scope.enableCancel = ! _.includes(["login", "register"], adhEmbed.getContext());

            scope.cancel = () => {
                 adhTopLevelState.goToCameFrom("/");
            };

            var handleErrors = (errors) => {
                bindServerErrors(scope, errors);
                scope.credentials.password = "";
                scope.loginForm.$setPristine();
            };

            scope.logInWithServiceKonto = () => {
                var popup;

                var cancel = adhCrossWindowMessaging.on("serviceKontoToken", (data) => {
                    adhUser.logInWithServiceKonto(data.token).then(() => {
                        adhTopLevelState.goToCameFrom("/", true);
                    }, handleErrors);

                    popup.close();
                    cancel();
                });

                popup = $window.open(adhConfig.service_konto_login_url, "_blank", "width=460,height=225");
            };

            scope.logIn = () => {
{'fraction_non_alphanumeric': 0.12594976783452932, 'fraction_numerical': 0.001055297593921486, 'mean_word_length': 2.4535349854227406, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2500554', 'n_tokens_mistral': 5387, 'n_tokens_neox': 5224, 'n_words': 1518}