PageSourceSearch

https://mycouncil.milton-keynes.gov.uk/js/core/userProfile.js

js milton-keynes.gov.uk collected 2026-10-02 04:09:12 UTC 13,937 bytes, 401 lines download raw bytes

1window.FS = window.FS || {};
2window.FS.Profile = (function() { 
3    var throwError = function(message) {
4        return function(error) {
5            var msg = 'An error occurred while ' + message;
6            if (error && error.message) {
7                msg += ': ' + error.message;
8            } else {
9                msg += '.';
10            }
11            throw new Error(msg);
12        };
13    };
14
15    var getPath = function(path, obj) {
16        var dotPos = path.indexOf('.');
17        var parPos = [path.indexOf('['), path.indexOf(']')];
18        var head, tail, idx;
19
20        // If the first symbol we encounter is a '.'
21        if(dotPos > -1 && (dotPos < parPos[0] || parPos[0] === -1)) {
22            head = path.slice(0, dotPos);
23            tail = path.slice(dotPos + 1);
24            if(obj[head]) {
25                if(tail) {
26                    return getPath(tail, obj[head]);
27                }
28                return obj[head];
29            }
30            return undefined;
31        }
32
33        // If the first symbol we encounter is a '[' (and there is a ']' after)
34        if(parPos[0] > -1 && parPos[1] > -1 && parPos[0] > dotPos && parPos[0] < parPos[1]) {
35            head = path.slice(0, parPos[0]);
36            idx = parseInt(path.slice(parPos[0] + 1, parPos[1]), 10);
37            tail = path.slice(parPos[1] + 1);
38            if((idx || idx === 0) && obj[idx]) {
39                if(tail) {
40                    return getPath(tail, obj[idx]);
41                }
42                return obj[idx];
43            }
44            return undefined;
45        }
46
47        // Otherwise, return it by key
48        return obj && path && obj[path] || undefined;
49    };
50
51    var timesSaved = 0;
52
53    var Profile = function() {
54        this._profile = null;
55        this._ucrn = null;
56        this._xref = [];
57    };
58
59    Profile.prototype.addressFields = ['Flat', 'House', 'Street', 'Locality', 'Town', 'Post_Town', 'County', 'Postcode', 'UPRN', 'country_id'];
60
61    Profile.prototype.getFullAddress = function(){
62        return this.get().then(function(userProfile){ 
63            if(userProfile.address && userProfile.address_id){
64                var root = userProfile.address[userProfile.address_id],
65                    full_address_array = [root.flat , root.house, root.street, root.town, root.county, root.postcode, root.country];
66
67                return _.reduce(full_address_array, function(prev, curr, index, orig){
68                    var comma = (prev == "") ? "" : ",";
69                    return (curr !== "" ) ? (prev + comma + curr) : ""; 
70                }, "");            
71            } 
72            else{return "";}
73        });
74    };
75
76    Profile.prototype.getPostcode = function(){
77        return this.get().then(function(userProfile){
78            if(userProfile.address && userProfile.address_id){
79                return userProfile.address[userProfile.address_id].postcode;
80            }
81            else{return "";}
82        });    
83    };
84
85    Profile.prototype.getUPRN = function(){
86        return this.get().then(function(userProfile){ 
87            if(userProfile.address && userProfile.address_id){
88                return userProfile.address[userProfile.address_id].uprn || "";
89            }
90            else{return "";}
91        });
92    };
93
94    Profile.prototype._fetchXrefs = _.once(function() {
95        return FS.API.get('self-getxref')
96        .caught(throwError('fetching your cross-references'))
97        .then(function(data) {
98            if(data.id) {
99                this._ucrn = data.id;
100            }
101
102            if(data.references) {
103                this._xref = data.references;
104            }
105
106            return {
107                ucrn: this._ucrn,
108                xref: this._xref
109            };
110        })
111        .caught(function(){
112            return "";
113        });
114    });
115
116    Profile.prototype.transformDrupalErrors = function(error){
117        switch (error) {
118            case !!error.match(/No current user id/g):
119                error = "You cannot change your email when registering an account";
120                break;
121        }
122
123        return error;
124    };
125
126
127    Profile.prototype._fetchProfile = _.memoize(function() {
128        return FS.Auth.isLoggedIn()
129        .then(function(session) {
130            if(!session.is_authenticated) {
131                throw new Error('You are not logged in.');
132            }
133
134            return FS.API.get('Self-Sphinx');
135        })
136        .caught(throwError('fetching your profile data'))
137        .then(function(sphinx) {
138            if(parseInt(sphinx.is_error, 10)) {
139                throw new Error(sphinx.error);
140            }
141
142            var profile = sphinx.count && _.find(sphinx.values, function(p) { return p.id; });
143
144            if(profile) {
145                this._profile = _.clone(profile);
146            }
147
148            return profile ? this._profile : false;
149        })
150        .caught(throwError('reading your profile data'));
151    }, function() { return timesSaved; });
152
153    /*
154     * @method FS.Profile.get
155     * @param <String> path: A JS expression describing the element of the profile to return.
156     *      i.e. 'id' or 'account.status'
157     * @returns A Promise to get the profile item represented by path. If path is not specified, the whole profile is returned.
158     */
159    Profile.prototype.get = function(path) {
160        return (this._profile ? Promise.resolve(this._profile) : this._fetchProfile())
161        .caught(function(error) {
162            return {};
163        })
164        .then(function(profile) {
165            return _.clone(path ? getPath(path, profile) : profile);
166        });
167    };
168
169    /*
170     * @method FS.Profile.getForce
171     * Forces clearing profile result of previous fetching operation
172     * @param <String> path: A JS expression describing the element of the profile to return.
173     *      i.e. 'id' or 'account.status'
174     * @returns A Promise to get the profile item represented by path. If path is not specified, the whole profile is returned.
175    */
176    Profile.prototype.getForce = function (path) {
177        delete this._profile;
178        timesSaved++;
179        return this.get(path);
180    };
181
182    /*
183     * @method FS.Profile.getXref
184     * @param <String|Object|Function> match: If a string, then match on type name. Otherwise, pass as comparator to _.where
185     * @param <String> path: An optional JS expression describing the element of the xref to return.
186     */
187    Profile.prototype.getXref = function(match, path) {
188        var method = 'find';
189        if(_.isString(match)) {
190            match = { type: match };
191        }
192        if(_.isObject(match)) {
193            method += 'Where';
194        }
195
196        return this._fetchXrefs()
197        .then(function(xrefs) {
198            if(!match && !path) return xrefs;
199
200            var xref = _[method](xrefs.xref || [], match);
201
202            return path ? getPath(path, xref) : xref;
203        });
204    };
205    
206    Profile.prototype._getPrimary = function(args) {
207        return this.get(args.type + '_id')
208        .bind(this)
209        .then(function(id) {
210            var subPath = [args.type, id];
211            if(args.path) {
212                subPath.push(args.path);
213            }
214            return Promise.props({
215                "isInprofile": this.get(subPath.join('.')),
216                "session": FS.Auth.isLoggedIn()
217            })
218            .bind(this)
219            .then(function(data){
220                if (data.isInprofile) return data.isInprofile;
221                else {
222                    return data.session ? this.createPath(data.session, args.session_path) : undefined;
223                }
224
225            });
226        });
227    };
228
229    Profile.prototype.createPath = function(obj, keyPath) {
230        
231        var result;
232        _.each(keyPath, function(key){
233            var scope = result ? result : obj;
234            result =  scope[key];
235        });
236
237        return result;
238
239    };
240
241    /*
242     * @method FS.Profile.getPrimaryPhone
243     * @param <String> path: An optional JS expression describing the element of the phone to return.
244     */
245    /*
246     * @method FS.Profile.getPrimaryAddress
247     * @param <String> path: An optional JS expression describing the element of the address to return.
248     */
249    /*
250     * @method FS.Profile.getPrimaryEmail
251     * @param <String> path: An optional JS expression describing the element of the email to return.
252     * @param <array> session_path: An optional JS expression describing the path to data within the session object.
253     */
254
255    var primaryDetails = [{
256        "name": 'Phone'
257    }, {
258        "name": 'Address'
259    }, {
260        "name": 'Email',
261        "path": ["email"],
262        "session_path": ["user", "email"]
263    }];
264
265    _.each(primaryDetails, function(details) {
266        Profile.prototype['getPrimary' + details.name] = _.partial(Profile.prototype._getPrimary, {
267            "type"           : details.name.toLowerCase(),
268            "path"           : details.path,
269            "session_path"   : details.session_path
270        });
271    });
272
273    /*
274     * @method FS.Profile._fromProfileForm
275     * @param <Object> newProfile: Profile data from the profile wizard form
276     * @returns 
277     */
278    Profile.prototype._fromProfileForm = function(profile) {
279        // All of these values take hard-coded defaults
280        var output = {
281            contact_type: profile.contact_type || 'Individual',
282            preferred_language: 'en_GB',            
283            'custom_Account_Information[Self-Service_Account]': 'yes'
284        };
285
286        if (profile.AllowSharingAcrossOrganisation) {
287            output['custom_Additional_Details[Consent_To_Share_]'] = (profile.AllowSharingAcrossOrganisation === 'Yes') ? 1 : 0;
288        };
289
290        if(profile.id) {
291            output.contact_id = profile.id;
292        }
293
294        if(profile.ucrn) {
295            output['custom_Account_Information[UCRN]'] = profile.ucrn;
296        }
297
298        // Set basic profile details
299        output.title        = profile.title;
300        output.first_name  = profile.first_name;
301        output.last_name   = profile.last_name;
302        output.prefix_id   = parseInt(profile.prefix_id, 10) || 0;
303        
304        if(profile.gender_id === 'Male'){
305            output.gender_id = 2;
306        } 
307        else if(profile.gender_id === 'Female'){
308            output.gender_id = 1;
309        }
310        else{
311            output.gender_id = null;
312        }
313
314        // Set default contact method
315        output['custom_Additional_Details[Preferred_Contact_Method]'] = parseInt(profile.preferred_contact_method_id || profile.contact_method_id, 10) || 0;
316
317        // Set date of birth
318        if (profile.birth_date) {
319            output.birth_date = profile.birth_date.split(/[^0-9]/g).reverse().join('-');
320        }
321
322        // Set phone numbers
323        var phoneCount = 0;
324        _.each([1, 2], function(i) {
325            var phone = profile['phone' + i];
326            if(phone) {
327                var id = profile['phone' + i + '_id'] || phoneCount++;
328                var set = function(k, v) {
329                    output['phone[' + id + '][' + k + ']'] = v;
330                };
331                set('phone', phone);
332                set('phone_type_id', i === 2 ? 3 : 1);
333                set('is_billing', 1);
334                set('is_primary', 1);
335                set('location_type_id', 1);
336            }
337        });
338
339        // Set email address
340        var emailId = profile.email_id || 0;
341        var setEmail = function(k, v) {
342            output['email[' + emailId + '][' + k + ']'] = v;
343        };
344        setEmail('email', profile.email);
345        setEmail('is_billing', 1);
346        setEmail('is_primary', 1);
347        setEmail('location_type_id', 1);
348        setEmail('is_bulkmail', 0);
349        if(profile.email)   output['email'] = profile.email;
350
351        // Set address
352        var addressId = profile.address_id || 0;
353        var setAddress = function(k, v) {
354            output['custom_Address[' + addressId + '][' + k + ']'] = v;
355        };
356        _.each(['Flat', 'House', 'Street', 'Locality', 'Town', 'Post_Town', 'County', 'Postcode', 'UPRN', 'country_id'], function(field) {
357            var lower = field.toLowerCase();
358            if(profile.address){
359                return lower ? setAddress(field, profile.address[lower]) : "";
360            }
361            else{
362                return lower ? setAddress(field, profile[lower]) : "";
363            }
364        });
365
366        setAddress('Start_Date_', moment().format('YYYY-MM-DD'));
367        setAddress('is_primary', 1);
368        setAddress('Search_for_street_Postcode', [
369            output.address_house, output.address_street, output.address_postcode
370        ].join('::'));
371        setAddress('location_type_id', 1);
372        setAddress('address_type', 1);
373        
374        // Add extra fields for internal sites
375        if(profile.national_insurance)  output['custom_Additional_Details[National_Insurance]'] = profile.national_insurance;
376        if(profile.manager)             output['custom_Additional_Details[Manager]'] = profile.manager;
377        if(profile.department)          output['custom_Additional_Details[Department]'] = profile.department;
378        if(profile.employee_number)     output['custom_Additional_Details[Employee_Number]'] = profile.employee_number;
379
380        return output;
381    };
382    
383    Profile.prototype.save = function(newProfile, raw) {
384        if(!raw) {
385            newProfile = this._fromProfileForm(newProfile);
386        }
387
388        var apiToUse = 'self-' + (newProfile.contact_id ? 'updatecustomer' : 'createcustomer-userchain');
389        return FS.API.postform(apiToUse, {"product": "self"} , newProfile)
390        .caught(throwError('saving your profile'))
391        .bind(this)
392        .then(function(result) {
393            if(parseInt(result.is_error, 10)) {
394                throw new Error(result.error);
395            }
396            timesSaved++;
397            return this._fetchProfile();
398        });    
399    };
400    return new Profile();
401}());

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.