PageSourceSearch

https://app.exabler.com/app/components/authentication/authentication.signup.ctrl.js

js exabler.com collected 2026-10-01 13:06:04 UTC 23,107 bytes, 625 lines download raw bytes

1/**
2 * PROVIDER PAYLOAD
3 * {base_plan_id}:{email}:{name}:{company}
4 *
5 * 8:[email protected]:Chris+Woodington:XYZ+Chambers+Ltd.
6 * @example ODpjd29vZGluZ3RvbkBnbWFpbC5jb206Q2hyaXMrV29vZGluZ3RvbjpYWVorQ2hhbWJlcnMrTHRkLg==
7 *
8 * Soft invite created outside the application. Service framework is picked up from the base_plan table
9 *
10 * TRADER PAYLOAD
11 * This controller handles links provided in invites sent to traders
12 * Route (defined in app.js) is '/signup/:payload?'
13 *
14 * Payload is a URL-safe base64 encoded string allowing to link the invite from email.
15 * It consists of 10 parts, separated with colons, following this structure:
16 *
17 * id:from_orgid:from_role:to_uid:to_role:provider_workflow:to_orgid:invite_date:platform:signature
18 *
19 * @example payload NjBlMGU1NDQtNzY4Yi00M2U2LWIwNzktMjkxOTVjODBiM2MwOjc0NDo0OTU6cHJvdmlkZXI6NDk1OnRyYWRlcjpzb21lc3RyaW5nOjEyMzoxNjEyNDE1MTEyMTI6bWFya2V0cGxhY2U6c2lnbmF0dXJlc3RyaW5n
20 * corresponds to
21 * 60e0e544-768b-43e6-b079-29195c80b3c0:744:495:provider:495:trader:somestring:123:161241511212:marketplace:signaturestring
22 */
23app.controller("signupCtrl", function (
24    $scope, $rootScope,
25    $routeParams,
26    $location,
27    $http,
28    tbServices,
29    Data,
30    AuthService,
31    accountServices,
32    WorkflowService,
33    apiServices,
34    AclService,
35    TradeModelService
36) {
37
38    try {
39        JL('signupCtrl').debug("Entered signupCtrl");
40    } catch (e) {}
41
42    var trader_plans = [
43        {id: 0, description: "Free", routes: []},
44        {id: 1, description: "Basic", routes: ["marketplace"]},
45        {id: 2, description: "Pro", routes: ["marketplace", "invite"]},
46        {id: 3, description: "OperatorX", routes: ["invite", "captiveX"]}
47    ];
48
49    // this is for extra data - separate table contains this - to remove
50    var provider_plans = [
51        {id: 0, description: "Free", routes: []},
52        {id: 1, description: "Basic", routes: ["marketplace"]},
53        {id: 2, description: "Pro", routes: ["marketplace", "invite"]}
54    ];
55
56    //TODO - to replace by api lookup to plan?
57    $scope.service_provider_plans = [
58        {base_plan_id: 6, description: "We provide transportation & logistics services"},
59        {base_plan_id: 8, description: "We provide only customs brokerage services"},
60        {base_plan_id: 7, description: "We provide customs consultancy"},
61        {base_plan_id: 9, description: "We provide financial services "},
62    ];
63
64    $scope.available_plans = [];
65
66    /**
67     * 6    Transport provider
68     7    Customs planning
69     8    Customs agent
70     9    Finance provider
71
72     */
73
74    var ctrl = this;
75    ctrl.view = {
76        isOpenAccess: true,
77        step2: false,
78        //  logo_url: "/images/exabler-small.png"
79    };
80
81    ctrl.invite = {};
82    var serviceBase = "/api/v1";
83
84    ctrl.signup = {
85        email: "",
86        name: "",
87        organisation: "",
88        operationcountry: "",
89        base_plan_id: '',
90        password: '',
91        soft_invite: false,
92        extra_data: angular.copy(OrganisationClass)
93    };
94
95
96    let domain = $location.host();
97
98    ctrl.isStep1Complete = function () {
99
100        if (!ctrl.signup.base_plan_id || !ctrl.signup.email || !ctrl.signup.password) return false;
101        return ctrl.signup.base_plan_id !== '' && ctrl.signup.email !== '' && ctrl.signup.password != ''
102
103    }
104    
105    ctrl.clickedNext = function() {
106        try { JL('signupCtrl').info({mx_event: "Clicked Next on provider signup"}); } catch {}
107    }
108
109    ctrl.isFormComplete = function () {
110
111        return ctrl.signup.base_plan_id && ctrl.signup.email && ctrl.signup.password && ctrl.signup.name && ctrl.signup.company && ctrl.signup.operationcountry && ctrl.signup.acceptance
112
113    }
114
115    ctrl.view.payloadPresent = typeof $routeParams.payload != 'undefined';
116
117    var onInit = function () {
118        
119        try { JL('signupCtrl').debug("Initialising signupCtrl"); } catch (e) {}
120        // $scope.countries = tbServices.service('country').src();
121        $scope.countries = TradeModelService.ordered_countries_list;
122
123        if ($location.$$path === '/provider-signup') {
124
125            try {
126                JL('signupCtrl').info("Got to provider-signup");
127            } catch (e) {
128                console.error("Failed to log error");
129            }
130            // provider with payload
131            if (typeof $routeParams.payload != 'undefined') {
132
133
134                // decode payload
135                ctrl.payload = atob(String($routeParams.payload));
136                // check payload format validity
137                if (ctrl.payload.indexOf(':') <= 0) {
138                    return setInvalid();
139                }
140                // split payload into array
141                var paramsArray = ctrl.payload.split(":");
142                // verify params count
143                if (paramsArray.length != 4) {
144                    return setInvalid();
145                }
146
147
148                ctrl.signup.soft_invite = true;
149
150                ctrl.signup.base_plan_id = paramsArray[0];
151                ctrl.signup.email = paramsArray[1];
152                ctrl.signup.name = decodeUrlParameter(paramsArray[2]);
153                ctrl.signup.company = decodeUrlParameter(paramsArray[3]);
154
155
156                $http.get('/data/operators.php/?p=' + ctrl.signup.base_plan_id).then((result) => {
157
158                    ctrl.view.logo_url = result.data[0].logo_url;
159                    ctrl.view.operator_info = result.data[0];
160
161                    if (result.data[0].owner == 'Exabler.com') {
162                        ctrl.view.isOpenAccess = true;
163                    } else {
164                        ctrl.view.isOpenAccess = false;
165                    }
166
167
168                });
169
170
171                ctrl.signup.operationcountry = "GB";
172
173            } else {
174
175                // independent provider signup 
176
177                // todo: copy from above make standard call
178                // this one retrieves based on the traders invited plan
179                $http.get('/data/operators.php/?p=0').then((result) => {
180
181                    ctrl.view.logo_url = result.data[0].logo_url;
182                    ctrl.view.operator_info = result.data[0];
183
184                    if (result.data[0].owner == 'Exabler.com') {
185                        ctrl.view.isOpenAccess = true;
186                    } else {
187                        ctrl.view.isOpenAccess = false;
188                        ctrl.view.offer_details = result.data[0].offer_details;
189                    }
190
191                });
192
193
194            }
195
196
197        }
198        // check if payload is present on the trader invite
199        else if (typeof $routeParams.payload == 'undefined') {
200
201            try { JL('signupCtrl').debug("No payload. Getting operators"); } catch (e) {}// todo: copy from above make standard call
202            // this one retrieves based on the traders invited plan
203            $http.get('/data/operators.php/?p=0').then((result) => {
204
205                ctrl.view.logo_url = result.data[0].logo_url;
206                ctrl.view.operator_info = result.data[0];
207
208                if (result.data[0].owner == 'Exabler.com') {
209                    ctrl.view.isOpenAccess = true;
210                } else {
211                    ctrl.view.isOpenAccess = false;
212                    ctrl.view.offer_details = result.data[0].offer_details;
213                }
214
215            });
216
217
218            try {
219                JL('signupCtrl').debug("Entered provider-signup without payload");
220            } catch (e) {
221                console.error("Failed to log error");
222            }
223            ctrl.invite.expired = false;
224            // ctrl.signup = {
225            //     email: "",
226            //     name: "",
227            //     organisation: "",
228            //     operationcountry: "",
229            //     extra_data: angular.copy(OrganisationClass)
230            // };
231
232        } else {
233
234            try { JL('signupCtrl').debug("Decoding payload"); } catch (e) {}// decode payload    
235            ctrl.payload = atob(String($routeParams.payload));
236            // check payload format validity
237            if (ctrl.payload.indexOf(':') <= 0) {
238                return setInvalid();
239            }
240            // split payload into array
241            var paramsArray = ctrl.payload.split(":");
242            // verify params count
243            if (paramsArray.length != 11) {
244                return setInvalid();
245            }
246
247            let params = {
248                id: paramsArray[0],
249                from_orgid: paramsArray[1],
250                from_role: paramsArray[2],
251                // from_organisation: paramsArray[3],     
252                to_uid: paramsArray[3],
253                to_role: paramsArray[4],
254                provider_workflow: paramsArray[5],
255                to_orgid: paramsArray[6],
256                operationcountry: paramsArray[7],
257                invite_date: paramsArray[8],
258                platform: paramsArray[9],
259                signature: paramsArray[10]
260            };
261            // check first one is a uuid
262            if (params.id.match(/^[a-z]{3}[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i) > 1) {
263                return setInvalid();
264            }
265            // check from_orgid format validity
266            if (isNaN(parseInt(params.from_orgid))) {
267                return setInvalid();
268            }
269            // check signature format validity
270            // if(params.signature.toString().length!=64) {
271            //     return setInvalid();
272            // }
273            ctrl.invite = params;
274            ctrl.invite.valid = true;
275            try { JL('signupCtrl').debug("Verifying joincode"); } catch (e) {}
276            $http.post(serviceBase + '/verifyjoincode', params)
277                .then(function (response) {
278                    if (response.data.status === "expired") {
279                        return setInvalid();
280                    }
281                    if (response.data.status === "revoked") {
282                        return setInvalid();
283                    }
284                    if (response.data.status != "pending" && response.data.status != "created") {
285                        throw new Error("unexpected response from server: " + JSON.stringify(response.data));
286                    }
287                    try { JL('signupCtrl').debug("Verified joincode"); } catch (e) {}
288                    if (response.data.from_org_name) {
289                        ctrl.invite.from_org_name = response.data.from_org_name;
290                    }
291                    if (response.data.organisation) {
292                        ctrl.invite.organisation = response.data.organisation;
293                    }
294                    if (response.data.name) {
295                        ctrl.invite.name = response.data.name;
296                    }
297                    if (response.data.email) {
298                        ctrl.invite.email = response.data.email;
299                    }
300                    if (response.data.operationcountry) {
301                        ctrl.invite.operationcountry = response.data.operationcountry;
302                    }
303                    if (response.data.available_plans) {
304                        $scope.available_plans = response.data.available_plans;
305                        ctrl.invite.base_plan_id = $scope.available_plans.filter((plan) => {
306                            return plan.selected
307                        })[0].base_plan_id;
308                    }
309                    if (response.data.up_chain_sponsor_orgid) {
310                        ctrl.invite.up_chain_sponsor_orgid = response.data.up_chain_sponsor_orgid;
311                    }
312                    if (response.data.up_chain_sponsor_object_id) {
313                        ctrl.invite.up_chain_sponsor_object_id = response.data.up_chain_sponsor_object_id;
314                    }
315                    try {
316                        const log_obj = {
317                            mx_event: "Invited trader visit sign up page",
318                            uid: params.to_uid,
319                            base_plan_id: ctrl.invite.base_plan_id
320                        };
321                        JL('signupCtrl').info(log_obj);
322                    } catch (e) {}
323
324                    try { JL('signupCtrl').debug("Getting operators"); } catch (e) {}
325                    // todo: copy from above make standard call
326                    // this one retrieves based on the traders invited plan
327                    $http.get('/data/operators.php/?p=' + ctrl.invite.base_plan_id).then((result) => {
328
329                        try { JL('signupCtrl').debug("Got operators"); } catch (e) {}
330                        ctrl.view.logo_url = result.data[0].logo_url;
331                        ctrl.view.operator_info = result.data[0];
332
333                        if (result.data[0].owner == 'Exabler.com') {
334                            ctrl.view.isOpenAccess = true;
335                        } else {
336                            ctrl.view.isOpenAccess = false;
337                            ctrl.view.offer_details = result.data[0].offer_details;
338                        }
339                    });
340
341
342                    ctrl.invite.valid = true;
343
344                })
345                .catch(function (error) {
346
347                    console.log('Unhandled exception: ' + JSON.stringify(error));
348                    try {
349                        JL('signupCtrl').error('Error - checking join code - ' + JSON.stringify(error));
350                    } catch (e) {
351                        console.error("Failed to log error");
352                    }
353                    //   $location.path("/login");
354
355                });
356
357        }
358
359    };
360
361    var setInvalid = function () {
362        ctrl.invite.expired = true;
363        ctrl.invite.valid = false;
364    }
365
366    onInit();
367
368
369    /**
370     * Update invited tblOrganisation and tblUser
371     * Sets credentials according to given email and password
372     */
373    $scope.signUp = function () {
374
375        try {
376            const log_obj = {mx_event: "Invited trader clicked Sign up"};
377            JL('signupCtrl').info(log_obj);
378        } catch(e) {}
379        $scope.disableSignupButton = true;
380        $http.post(serviceBase + '/usejoincode', ctrl.invite)
381            .then(function (response) {
382                console.debug(JSON.stringify(response.data));
383                return AuthService.login({
384                    email: ctrl.invite.email,
385                    password: ctrl.invite.password
386                });
387            })
388            .then(function success(response) {
389                if (response.status == "success") {
390
391                    // test login
392
393                    $rootScope.setCurrentUser(response);
394                    $rootScope.isUserLoggedin = true;
395                    $rootScope.authenticated = true;
396
397                    accountServices.getPlanDetails(response).then(function (plan_details) {
398                        $rootScope.plan_details = plan_details;
399                        WorkflowService.set_services();
400                    });
401
402                    let aclDataUser;
403                    try {
404                        // run api call to get roles
405                        aclDataUser = JSON.parse(response.permissions);
406                    } catch (e) {
407                        console.log("error reading permissions");
408                    }
409
410                    AclService.setAbilities(aclDataUser);
411
412                    // Attach the member role to the current user (not sure of the benefit)
413                    Object.keys(aclDataUser).forEach(key => {
414                        AclService.attachRole(key);
415                    });
416
417
418                    $location.path('/home');
419                } else if (response.status == "error") {
420
421                    try { JL('signupCtrl').error("Error - using join code - due to server error"); } catch {}
422                    $scope.disableSignupButton = false;
423                    //  $location.path('/login');
424
425                }
426            })
427            .catch(function (error) {
428                $scope.disableSignupButton = false;
429                console.error("Error: " + error.message);
430                Data.toast({status: error.status, message: error.message});
431                try {
432                    JL('signupCtrl').error('Error - using join code - ' + JSON.stringify(error));
433                } catch (e) {
434                    console.error("Failed to log error");
435                }
436
437                //       $location.path('/login');
438            });
439
440    };
441
442
443    /**
444     * Sign up without an invitation
445     */
446    $scope.independentSignUp = function (data) {
447
448        $scope.disableSignupButton = true;
449        try {
450            gtag('event', 'sign_up - TradingCompany', {'event_category': 'Signup', 'event_label': 'Sign up page TradingCompany'});
451            JL('signupCtrl').info("Independent signup");
452        } catch(e) {}
453        
454        var customer = Object.assign({}, data);
455
456        customer.type = "trader";
457        customer.name = "<your name>";
458
459        // legacy fields
460        customer.phone = "";
461        customer.organisation = data.company;
462        customer.title = "";
463        customer.jobfunction = "";
464
465        const timestamp = moment();
466        _.set(customer, "extra_data.created", timestamp);
467        _.set(customer, "extra_data.updated", timestamp);
468        const country_object = tbServices.service('country').getByAlpha2(data.operationcountry);
469        _.set(customer.extra_data, "registered_country", country_object);
470        _.set(customer.extra_data, "addresses.registered[0].country", country_object);
471        _.set(customer.extra_data, "addresses.trading[0].country", country_object);
472
473        customer.extra_data.id = "urg" + uuid();
474
475        // to remve
476        customer.extra_data.plan_selection = trader_plans[0];
477
478        // we don't know the uid for created_by or updated_by until created
479        ctrl.signup.extra_data = Object.assign({}, customer.extra_data); // update extra data object
480
481        customer.extra_data = JSON.stringify(customer.extra_data);
482        // customer.tradingAddress1 = customer.address;
483        // customer.contactName = customer.name;
484        Data.post("signUp", {customer: customer})
485            .then(function (results) {
486                ctrl.signup.type = customer.type;
487
488                Data.toast(results);
489
490                if (results.status == "success") {
491                    try {
492                        JL('signupCtrl').info({mx_event: "Independent trader signup", plan: customer.extra_data.plan_selection});
493                    } catch (e) {
494                    }
495
496                    // Finally go to the home page
497                    $location.path("/home");
498                } else {
499                    $scope.disableSignupButton = false;
500                }
501            })
502            .catch(function (error) {
503                $scope.disableSignupButton = false;
504                console.error("Error: " + error.data.message);
505                Data.toast(error.data);
506                try {
507                    JL('signupCtrl').error({mx_event: 'Error - independentSignUp', error: JSON.stringify(error)});
508                } catch (e) {
509                    console.error("Failed to log error");
510                }
511                //  $location.path('/login');
512            });
513    };
514
515
516    /**
517     * Self-signup for a provider
518     */
519    $scope.providerSelfSignUp = function (data) {
520
521        $scope.disableSignupButton = true;
522        try {
523            gtag('event', 'sign_up - ServiceProvider', {'event_category': 'Signup', 'event_label': 'Sign up page ServiceProvider'});
524            JL('signupCtrl').info("Provider self signup");
525        } catch(e) {}
526
527        var customer = Object.assign({}, data);
528        customer.type = "svc";
529
530        if (!customer.soft_invite) {
531            // no longer required
532            //customer.name = "<your name>";
533        }
534
535        // legacy fields
536        customer.phone = "";
537        customer.organisation = data.company;
538        // customer.extra_data.registered_name = data.company;      // deprecated
539
540        customer.extra_data.registered_country = tbServices.service('country').getByAlpha2(data.operationcountry);
541        customer.extra_data.addresses.registered[0].country = tbServices.service('country').getByAlpha2(data.operationcountry);
542     
543        customer.operationcountry = data.operationcountry;
544        customer.extra_data.created = customer.extra_data.updated = moment();
545        customer.extra_data.id = "urg" + uuid();
546
547        // @ramin - not sure what this is doing
548        // plan this is in extra data and shows free
549        customer.extra_data.plan_selection = provider_plans[0];
550
551        // we don't know the uid for created_by or updated_by until created
552        ctrl.signup.extra_data = Object.assign({}, customer.extra_data); // update extra data object
553
554        $http.post(serviceBase + "/provider-signup", {customer: customer})
555            .then(function (results) {
556                ctrl.signup.type = customer.type;
557
558                if (results.statusText === "OK") {
559                    try {
560                        JL('signupCtrl').info({mx_event: "Independent SP signup", plan: customer.extra_data.plan_selection});
561                    } catch (e) {
562                    }
563
564                    // Finally go to the home page
565                    $location.path("/home");
566                }
567            })
568            .catch(function (error) {
569                $scope.disableSignupButton = false;
570                console.error("Error: " + error.message);
571                Data.toast({status: error.data.status, message: error.data.message});
572                try {
573                    JL('signupCtrl').error('Error - providerSelfSignUp - ' + JSON.stringify(error.data));
574                } catch (e) {
575                    console.error("Failed to log error");
576                }
577                // $location.path('/login');
578            });
579
580
581    };
582
583
584    var strongRegularExp = new RegExp("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})");
585    var mediumRegularExp = new RegExp("^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})");
586
587    $scope.checkPwdStrength = {
588        "color": "white",
589        "font-size": "8pt",
590    };
591    $scope.pwd_match = true;
592
593    $scope.validationInputPwdText = function (value) {
594
595        if (strongRegularExp.test(value)) {
596            $scope.checkPwdStrength["background-color"] = "green";
597            $scope.feedback = 'Strong';
598        } else if (mediumRegularExp.test(value)) {
599            $scope.checkPwdStrength["background-color"] = "orange";
600            $scope.feedback = 'OK';
601        } else {
602            $scope.checkPwdStrength["background-color"] = "red";
603            $scope.feedback = "Weak";
604        }
605    };
606
607    $scope.matchPasswords = function (ref_pwd) {
608        if ((ref_pwd !== ctrl.password_confirm) && ref_pwd && ctrl.password_confirm) {
609            $scope.pwd_match = false;
610        } else {
611            $scope.pwd_match = true;
612        }
613        $scope.pwd_match = true;
614
615    }
616
617
618});
619
620
621function decodeUrlParameter(str) {
622    return decodeURIComponent((str + '').replace(/\+/g, '%20'));
623}
624
625

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.