cyclid-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +178 -0
- data/README.md +20 -0
- data/app/cyclid_ui.rb +124 -0
- data/app/cyclid_ui/config.rb +64 -0
- data/app/cyclid_ui/controllers/auth.rb +102 -0
- data/app/cyclid_ui/controllers/base.rb +41 -0
- data/app/cyclid_ui/controllers/health.rb +96 -0
- data/app/cyclid_ui/controllers/organization.rb +64 -0
- data/app/cyclid_ui/controllers/user.rb +40 -0
- data/app/cyclid_ui/helpers.rb +55 -0
- data/app/cyclid_ui/memcache.rb +45 -0
- data/app/cyclid_ui/models/user.rb +91 -0
- data/app/cyclid_ui/templates/footer.mustache +8 -0
- data/app/cyclid_ui/templates/job.mustache +21 -0
- data/app/cyclid_ui/templates/job_info.mustache +40 -0
- data/app/cyclid_ui/templates/layout.mustache +102 -0
- data/app/cyclid_ui/templates/login.mustache +78 -0
- data/app/cyclid_ui/templates/organization.mustache +150 -0
- data/app/cyclid_ui/templates/user.mustache +97 -0
- data/app/cyclid_ui/views/job.rb +25 -0
- data/app/cyclid_ui/views/layout.rb +52 -0
- data/app/cyclid_ui/views/login.rb +25 -0
- data/app/cyclid_ui/views/organization.rb +25 -0
- data/app/cyclid_ui/views/user.rb +25 -0
- data/bin/cyclid-ui-assets +17 -0
- data/lib/cyclid_ui/app.rb +4 -0
- data/public/images/LICENSE +3 -0
- data/public/images/cyclid-logo-large.png +0 -0
- data/public/images/favicon16.png +0 -0
- data/public/images/favicon32.png +0 -0
- data/public/images/favicon48.png +0 -0
- data/public/images/favicon64.png +0 -0
- data/public/images/favicon96.png +0 -0
- data/public/js/api.js +34 -0
- data/public/js/cyclid.js +32 -0
- data/public/js/job.js +215 -0
- data/public/js/organization.js +345 -0
- data/public/js/user.js +145 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.css +587 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.css.map +1 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.min.css +6 -0
- data/public/vendor/bootstrap/css/bootstrap-theme.min.css.map +1 -0
- data/public/vendor/bootstrap/css/bootstrap.css +6760 -0
- data/public/vendor/bootstrap/css/bootstrap.css.map +1 -0
- data/public/vendor/bootstrap/css/bootstrap.min.css +6 -0
- data/public/vendor/bootstrap/css/bootstrap.min.css.map +1 -0
- data/public/vendor/bootstrap/css/custom.css +193 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/public/vendor/bootstrap/js/bootstrap.js +2363 -0
- data/public/vendor/bootstrap/js/bootstrap.min.js +7 -0
- data/public/vendor/bootstrap/js/npm.js +13 -0
- data/public/vendor/font-awesome/HELP-US-OUT.txt +7 -0
- data/public/vendor/font-awesome/css/font-awesome.css +2199 -0
- data/public/vendor/font-awesome/css/font-awesome.min.css +4 -0
- data/public/vendor/font-awesome/fonts/FontAwesome.otf +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.eot +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.svg +685 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.woff +0 -0
- data/public/vendor/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
- data/public/vendor/font-awesome/less/animated.less +34 -0
- data/public/vendor/font-awesome/less/bordered-pulled.less +25 -0
- data/public/vendor/font-awesome/less/core.less +12 -0
- data/public/vendor/font-awesome/less/fixed-width.less +6 -0
- data/public/vendor/font-awesome/less/font-awesome.less +18 -0
- data/public/vendor/font-awesome/less/icons.less +733 -0
- data/public/vendor/font-awesome/less/larger.less +13 -0
- data/public/vendor/font-awesome/less/list.less +19 -0
- data/public/vendor/font-awesome/less/mixins.less +60 -0
- data/public/vendor/font-awesome/less/path.less +15 -0
- data/public/vendor/font-awesome/less/rotated-flipped.less +20 -0
- data/public/vendor/font-awesome/less/screen-reader.less +5 -0
- data/public/vendor/font-awesome/less/stacked.less +20 -0
- data/public/vendor/font-awesome/less/variables.less +744 -0
- data/public/vendor/font-awesome/scss/_animated.scss +34 -0
- data/public/vendor/font-awesome/scss/_bordered-pulled.scss +25 -0
- data/public/vendor/font-awesome/scss/_core.scss +12 -0
- data/public/vendor/font-awesome/scss/_fixed-width.scss +6 -0
- data/public/vendor/font-awesome/scss/_icons.scss +733 -0
- data/public/vendor/font-awesome/scss/_larger.scss +13 -0
- data/public/vendor/font-awesome/scss/_list.scss +19 -0
- data/public/vendor/font-awesome/scss/_mixins.scss +60 -0
- data/public/vendor/font-awesome/scss/_path.scss +15 -0
- data/public/vendor/font-awesome/scss/_rotated-flipped.scss +20 -0
- data/public/vendor/font-awesome/scss/_screen-reader.scss +5 -0
- data/public/vendor/font-awesome/scss/_stacked.scss +20 -0
- data/public/vendor/font-awesome/scss/_variables.scss +744 -0
- data/public/vendor/font-awesome/scss/font-awesome.scss +18 -0
- data/public/vendor/jquery-2.2.4.min.js +4 -0
- data/public/vendor/jquery.md5.js +269 -0
- data/public/vendor/js.cookie.js +151 -0
- data/public/vendor/mustache.min.js +1 -0
- metadata +322 -0
@@ -0,0 +1,345 @@
|
|
1
|
+
function org_show_job() {
|
2
|
+
var job_id = $(this).data('job_id');
|
3
|
+
var job_info_inner = $('#job-info-inner').html();
|
4
|
+
|
5
|
+
$(`#collapse${job_id}`).html(job_info_inner);
|
6
|
+
|
7
|
+
var url = `${gblOrganizationURL}/jobs/${job_id}`;
|
8
|
+
api_get(url, gblUsername, ji_update_all, ji_get_failed);
|
9
|
+
|
10
|
+
// Watch the job for status updates
|
11
|
+
(function(j, u) {
|
12
|
+
addNamedInterval(`watcher${j}`,
|
13
|
+
function() { ji_watch_job(u); },
|
14
|
+
3000);
|
15
|
+
})(job_id, url);
|
16
|
+
|
17
|
+
// Mark the parent row as active
|
18
|
+
$(`#row${job_id}`).addClass('active');
|
19
|
+
}
|
20
|
+
|
21
|
+
function org_hide_job() {
|
22
|
+
var job_id = $(this).data('job_id');
|
23
|
+
|
24
|
+
// Clear any watchers
|
25
|
+
removeNamedInterval(`watcher${job_id}`);
|
26
|
+
|
27
|
+
// Remove the job info panel
|
28
|
+
$(`#collapse${job_id} > #job-info-panel`).remove();
|
29
|
+
|
30
|
+
// Remove the parent row active highlight
|
31
|
+
$(`#row${job_id}`).removeClass('active');
|
32
|
+
}
|
33
|
+
|
34
|
+
function org_add_job(job, append) {
|
35
|
+
var accordian = $('#job-accordian tbody');
|
36
|
+
|
37
|
+
var template = $('#job-info').html();
|
38
|
+
Mustache.parse(template);
|
39
|
+
|
40
|
+
var duration = ji_calculate_duration(job.started, job.ended);
|
41
|
+
|
42
|
+
var data = {id: job.id,
|
43
|
+
name: job.job_name,
|
44
|
+
started: new Date(job.started).toUTCString(),
|
45
|
+
duration: duration,
|
46
|
+
status: ji_job_status_to_indicator(job.status)};
|
47
|
+
|
48
|
+
var rendered = Mustache.render(template, data);
|
49
|
+
var row = $(rendered);
|
50
|
+
row.hide();
|
51
|
+
if( append ) {
|
52
|
+
accordian.append(row);
|
53
|
+
} else {
|
54
|
+
accordian.prepend(row);
|
55
|
+
}
|
56
|
+
row.fadeIn('slow');
|
57
|
+
|
58
|
+
// Add the job ID to the collapsable element so it can associate itself
|
59
|
+
// to the correct job
|
60
|
+
$(`#collapse${job.id}`).data('job_id', job.id);
|
61
|
+
|
62
|
+
// If the job is active, add it to the active list
|
63
|
+
if( window.active_jobs == undefined )
|
64
|
+
window.active_jobs = [];
|
65
|
+
|
66
|
+
if( ji_job_active(job.status) ){
|
67
|
+
var active = {job_id: job.id, status: job.status};
|
68
|
+
window.active_jobs.push(active);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
function org_job_list_failed(xhr) {
|
73
|
+
var failure_message = `Failed to retrieve job list<br>
|
74
|
+
<strong>${xhr.status}:</strong> ${xhr.responseText}`;
|
75
|
+
|
76
|
+
failure_message = `List failed: ${xhr.status}`;
|
77
|
+
$('#organization_failure > #error_message').html(failure_message);
|
78
|
+
|
79
|
+
$('#organization_failure').removeClass('hidden');
|
80
|
+
}
|
81
|
+
|
82
|
+
function org_update_job_list(jobs, append) {
|
83
|
+
console.log(jobs);
|
84
|
+
|
85
|
+
// Load the list
|
86
|
+
var records = jobs.records;
|
87
|
+
var length = records.length;
|
88
|
+
for( var i = length - 1; i >= 0; i-- ){
|
89
|
+
var job = records[i];
|
90
|
+
console.log(`job ${i}: ${JSON.stringify(job)}`);
|
91
|
+
|
92
|
+
org_add_job(job, append);
|
93
|
+
}
|
94
|
+
|
95
|
+
// Add collapse event handlers to each collapsable element to retrieve
|
96
|
+
// & remove the job info
|
97
|
+
$('.collapse').each(function(index) {
|
98
|
+
$(this).on('hidden.bs.collapse', org_hide_job);
|
99
|
+
$(this).on('show.bs.collapse', org_show_job);
|
100
|
+
});
|
101
|
+
// Ensure any active rows are properly hidden when a new one is shown
|
102
|
+
$('.collapse').on('show.bs.collapse', function () {
|
103
|
+
$('.collapse.in').collapse('hide');
|
104
|
+
});
|
105
|
+
|
106
|
+
// Show or hide the "Load more" button depending on if we're at the end of the list
|
107
|
+
if( gblOffset > 0 ) {
|
108
|
+
$('#org-load-more').removeClass('hidden');
|
109
|
+
} else {
|
110
|
+
$('#org-load-more').addClass('hidden');
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
function org_update_counter(total, loaded) {
|
115
|
+
var count = `Showing <strong>${total} - ${loaded + 1}</strong> of <strong>${total}</strong>`;
|
116
|
+
$('#org-counter').html(count);
|
117
|
+
}
|
118
|
+
|
119
|
+
function org_load_chunk(start) {
|
120
|
+
var limit = 100;
|
121
|
+
var offset = Math.max(start, limit) - limit;
|
122
|
+
|
123
|
+
// If we're on the last "chunk", there may be less than 'limit' jobs left to
|
124
|
+
// load. In that case we need to adjust the limit; we can cheat and use the
|
125
|
+
// currently set global offset which happens to be the total remainder of
|
126
|
+
// the jobs.
|
127
|
+
if( offset == 0){
|
128
|
+
limit = gblOffset;
|
129
|
+
}
|
130
|
+
console.log(`offset=${offset} limit=${limit} gblOffset=${gblOffset}`);
|
131
|
+
|
132
|
+
// Remember the current offset
|
133
|
+
gblOffset = offset;
|
134
|
+
|
135
|
+
// Update the counter
|
136
|
+
org_update_counter(gblTotal, gblOffset);
|
137
|
+
|
138
|
+
var url = `${gblOrganizationURL}/jobs?limit=${limit}&offset=${offset}`;
|
139
|
+
|
140
|
+
// Apply any search terms
|
141
|
+
var search = window.search;
|
142
|
+
if( ! $.isEmptyObject(search) ){
|
143
|
+
for( var s in search ){
|
144
|
+
url += `&${s}=${search[s]}`;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
console.log(`chunk url=${url}`);
|
148
|
+
|
149
|
+
api_get(url, gblUsername, function(jobs) { org_update_job_list(jobs, true); }, org_job_list_failed);
|
150
|
+
}
|
151
|
+
|
152
|
+
function org_apply_updates(stats) {
|
153
|
+
// Are there any new jobs?
|
154
|
+
var count = stats.total - gblTotal;
|
155
|
+
if( count > 0 ){
|
156
|
+
console.log(`loading ${count} new jobs...`);
|
157
|
+
|
158
|
+
var url = `${gblOrganizationURL}/jobs?limit=${count}&offset=${gblTotal}`;
|
159
|
+
api_get(url, gblUsername, function(jobs) { org_update_job_list(jobs, false); }, org_job_list_failed);
|
160
|
+
|
161
|
+
gblTotal = stats.total;
|
162
|
+
|
163
|
+
// Update the counter
|
164
|
+
org_update_counter(gblTotal, gblOffset);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
function org_apply_indicator_update(job, active, idx) {
|
169
|
+
console.log(`callback for job #${active.job_id}: old status is ${active.status}, new status is ${job.status}`);
|
170
|
+
if( job.status == 0 ){
|
171
|
+
console.log(`got a 0 status: ${JSON.stringify(job)}`);
|
172
|
+
}
|
173
|
+
|
174
|
+
if( job.status != active.status ){
|
175
|
+
console.log(`job #${job.job_id} status changed from ${active.status} to ${job.status}`);
|
176
|
+
|
177
|
+
var indicator = ji_job_status_to_indicator(job.status);
|
178
|
+
$(`#row${job.job_id} > #status`).html(indicator);
|
179
|
+
|
180
|
+
// Did the job finish? If so we can stop watching it
|
181
|
+
if( ji_job_finished(job.status) ) {
|
182
|
+
console.log(`job #${job.job_id} has finished; removing from active_jobs at position ${idx}`);
|
183
|
+
window.active_jobs.splice(idx, 1);
|
184
|
+
} else {
|
185
|
+
// Remember the current status
|
186
|
+
active.status = job.status;
|
187
|
+
window.active_jobs[idx] = active;
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
function org_watch_job_list() {
|
193
|
+
// Get the current total number of jobs
|
194
|
+
var url = `${gblOrganizationURL}/jobs?stats_only=true`;
|
195
|
+
|
196
|
+
// Apply any search terms
|
197
|
+
var search = window.search;
|
198
|
+
if( ! $.isEmptyObject(search) ){
|
199
|
+
for( var s in search ){
|
200
|
+
url += `&${s}=${search[s]}`;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
api_get(url, gblUsername, org_apply_updates, org_job_list_failed);
|
205
|
+
|
206
|
+
// Check the status of any current jobs
|
207
|
+
var length = window.active_jobs.length;
|
208
|
+
for( var idx = 0; idx < length; idx++ ){
|
209
|
+
var active = window.active_jobs[idx];
|
210
|
+
|
211
|
+
console.log(`checking status of job #${active.job_id}: current status is ${active.status}`);
|
212
|
+
|
213
|
+
(function(a, i){
|
214
|
+
url = `${gblOrganizationURL}/jobs/${active.job_id}/status`
|
215
|
+
api_get(url,
|
216
|
+
gblUsername,
|
217
|
+
function(job) { org_apply_indicator_update(job, a, i); },
|
218
|
+
org_job_list_failed);
|
219
|
+
})(active, idx);
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
function org_initialize_job_list(stats) {
|
224
|
+
console.log(stats);
|
225
|
+
|
226
|
+
gblTotal = stats.total;
|
227
|
+
gblOffset = gblTotal;
|
228
|
+
|
229
|
+
// Load the first set of jobs
|
230
|
+
org_load_chunk(gblTotal, 100);
|
231
|
+
|
232
|
+
// Watch for any new jobs
|
233
|
+
addNamedInterval('job_list', org_watch_job_list, 3000);
|
234
|
+
}
|
235
|
+
|
236
|
+
function org_clear_job_list() {
|
237
|
+
// Close any open job views
|
238
|
+
$('.collapse.in').collapse('hide');
|
239
|
+
|
240
|
+
// Remove any timers
|
241
|
+
clearAllNamedIntervals();
|
242
|
+
|
243
|
+
// Clear the active jobs list
|
244
|
+
window.active_jobs = [];
|
245
|
+
|
246
|
+
// Hide the "Load more" button if it's visible
|
247
|
+
$('#org-load-more').addClass('hidden');
|
248
|
+
|
249
|
+
// Clear the job list
|
250
|
+
$('#job-accordian tbody').empty();
|
251
|
+
|
252
|
+
// Reset job counts
|
253
|
+
gblTotal = 0;
|
254
|
+
gblOffset = 0;
|
255
|
+
|
256
|
+
// Reset the "x of y loaded" counter
|
257
|
+
org_update_counter(gblTotal, gblOffset);
|
258
|
+
}
|
259
|
+
|
260
|
+
function org_search_form_get() {
|
261
|
+
var name = $('#search_name').val();
|
262
|
+
var from = $('#search_from').val();
|
263
|
+
var to = $('#search_to').val();
|
264
|
+
var status = $('#search_status').val();
|
265
|
+
|
266
|
+
console.log(`name=${name} from=${from} to=${to} status=${status}`);
|
267
|
+
|
268
|
+
var search = {};
|
269
|
+
if( name != '' )
|
270
|
+
search['s_name'] = name;
|
271
|
+
if( from != '' )
|
272
|
+
search['s_from'] = new Date(from).toISOString();
|
273
|
+
if( to != '' )
|
274
|
+
search['s_to'] = new Date(to).toISOString();
|
275
|
+
if( status != 'Any' )
|
276
|
+
search['s_status'] = status;
|
277
|
+
|
278
|
+
return search;
|
279
|
+
}
|
280
|
+
|
281
|
+
function org_search_submit() {
|
282
|
+
var search = org_search_form_get();
|
283
|
+
console.log(`search=${search}`);
|
284
|
+
|
285
|
+
if( ! $.isEmptyObject(search) ){
|
286
|
+
// Remember the search terms that are being used
|
287
|
+
window.search = search;
|
288
|
+
|
289
|
+
// Reset the job list
|
290
|
+
org_clear_job_list();
|
291
|
+
|
292
|
+
// Find the number of jobs & load the initial set
|
293
|
+
var url = `${gblOrganizationURL}/jobs?stats_only=true`;
|
294
|
+
|
295
|
+
for( var s in search ){
|
296
|
+
url += `&${s}=${search[s]}`;
|
297
|
+
}
|
298
|
+
console.log(`search url=${url}`);
|
299
|
+
|
300
|
+
// Load the intial set of jobs
|
301
|
+
api_get(url, gblUsername, org_initialize_job_list, org_job_list_failed);
|
302
|
+
}
|
303
|
+
}
|
304
|
+
|
305
|
+
function org_search_form_reset() {
|
306
|
+
var search = window.search;
|
307
|
+
console.log(`search=${search}`);
|
308
|
+
|
309
|
+
// Don't do anything if the form is already clear
|
310
|
+
if( ! $.isEmptyObject(search) ){
|
311
|
+
$('#search_name').val('');
|
312
|
+
$('#search_from').val('');
|
313
|
+
$('#search_to').val('');
|
314
|
+
$('#search_status').val('Any');
|
315
|
+
|
316
|
+
$('#search_btn_clear').prop('disabled', true);
|
317
|
+
$('#search_btn_search').prop('disabled', true);
|
318
|
+
|
319
|
+
// Clear any saved search terms
|
320
|
+
window.search = {};
|
321
|
+
|
322
|
+
// Reset the job list
|
323
|
+
org_clear_job_list();
|
324
|
+
|
325
|
+
// Load the jobs from the start
|
326
|
+
var url = `${gblOrganizationURL}/jobs?stats_only=true`;
|
327
|
+
api_get(url, gblUsername, org_initialize_job_list, org_job_list_failed);
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
function org_search_form_changed() {
|
332
|
+
var search = org_search_form_get();
|
333
|
+
console.log(`search=${search}`);
|
334
|
+
|
335
|
+
// Enable or disable the Search & Clear buttons
|
336
|
+
if( $.isEmptyObject(search) ){
|
337
|
+
console.log('disabling');
|
338
|
+
$('#search_btn_clear').prop('disabled', true);
|
339
|
+
$('#search_btn_search').prop('disabled', true);
|
340
|
+
} else {
|
341
|
+
console.log('enabling');
|
342
|
+
$('#search_btn_clear').prop('disabled', false);
|
343
|
+
$('#search_btn_search').prop('disabled', false);
|
344
|
+
}
|
345
|
+
}
|
data/public/js/user.js
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
function user_show_error(msg){
|
2
|
+
$('#user_failure > #error_message').html(msg);
|
3
|
+
$('#user_failure').removeClass('hidden');
|
4
|
+
}
|
5
|
+
|
6
|
+
function user_get_failed(xhr){
|
7
|
+
var failure_message = `Failed to retrieve user details<br>
|
8
|
+
<strong>${xhr.status}:</strong> ${xhr.responseText}`;
|
9
|
+
failure_message = `Get failed: ${xhr.status}`;
|
10
|
+
|
11
|
+
user_show_error(failure_message);
|
12
|
+
}
|
13
|
+
|
14
|
+
function user_update_details(user){
|
15
|
+
console.log(JSON.stringify(user));
|
16
|
+
|
17
|
+
$('#user_heading').text(user.username);
|
18
|
+
|
19
|
+
name = user.name || user.username;
|
20
|
+
$('#user_name').text(name);
|
21
|
+
$('#user_email').text(user.email);
|
22
|
+
|
23
|
+
var length = user.organizations.length;
|
24
|
+
if( length > 0 ){
|
25
|
+
for(var i=0; i < length; i++){
|
26
|
+
var org = user.organizations[i];
|
27
|
+
var org_link = `<a href="#" id="user_config_${org}" download="${org}"><i class="fa fa-download" aria-hidden="true"></i> ${org}</a><br>`;
|
28
|
+
$('#user_org_list').append(org_link);
|
29
|
+
|
30
|
+
var config_org = $(`#user_config_${org}`);
|
31
|
+
config_org.data('org', org);
|
32
|
+
config_org.click(function(e) {
|
33
|
+
var org = $(this).data('org');
|
34
|
+
|
35
|
+
var config = `server: ${gblAPIURL}\n` +
|
36
|
+
`organization: ${org}\n` +
|
37
|
+
`username: ${user.username}\n` +
|
38
|
+
`secret: `;
|
39
|
+
|
40
|
+
console.log(`${org} was clicked: ${config}`);
|
41
|
+
|
42
|
+
this.href = "data:application/x-yaml," + encodeURIComponent(config);
|
43
|
+
});
|
44
|
+
}
|
45
|
+
} else {
|
46
|
+
$('#user_org_list').append('<em>None</em>');
|
47
|
+
}
|
48
|
+
|
49
|
+
$('#user_info').removeClass('hidden');
|
50
|
+
}
|
51
|
+
|
52
|
+
function user_password_secret_toggle() {
|
53
|
+
var secret = $('#user_password_secret');
|
54
|
+
|
55
|
+
// Toggle the disabled state on the 'secret' input; generate a new secret
|
56
|
+
// if one is required.
|
57
|
+
secret.prop('disabled', function(i, v) {
|
58
|
+
var key = secret.val();
|
59
|
+
if(v && !key){
|
60
|
+
// The key does not need to be cryptographically strong; just suitably
|
61
|
+
// unique
|
62
|
+
var key1 = Math.random().toString(36).substr(2,34);
|
63
|
+
var key2 = Math.random().toString(36).substr(2,34);
|
64
|
+
|
65
|
+
key = $.md5(key1 + key2);
|
66
|
+
secret.val(key);
|
67
|
+
}
|
68
|
+
return !v;
|
69
|
+
});
|
70
|
+
}
|
71
|
+
|
72
|
+
function user_password_form_reset() {
|
73
|
+
$('#user_password_failure').addClass('hidden');
|
74
|
+
$('#user_password_password_1').val('');
|
75
|
+
$('#user_password_password_2').val('');
|
76
|
+
$('#user_password_reset_signing').removeAttr('checked');
|
77
|
+
$('#user_password_secret').val('');
|
78
|
+
$('#user_password_secret').prop('disabled', true);
|
79
|
+
}
|
80
|
+
|
81
|
+
function user_password_update_failed(xhr){
|
82
|
+
var failure_message = `Failed to change password<br>
|
83
|
+
<strong>${xhr.status}:</strong> ${xhr.responseText}`;
|
84
|
+
failure_message = `Put failed: ${xhr.status}`;
|
85
|
+
|
86
|
+
user_show_error(failure_message);
|
87
|
+
}
|
88
|
+
|
89
|
+
function user_password_validate_submit() {
|
90
|
+
var password_1 = $('#user_password_password_1').val();
|
91
|
+
var password_2 = $('#user_password_password_2').val();
|
92
|
+
var change_secret = $('#user_password_reset_signing').is(':checked');
|
93
|
+
var secret = $('#user_password_secret').val();
|
94
|
+
|
95
|
+
console.log(`1=${password_1} 2=${password_2} change_secret=${change_secret} secret=${secret}`);
|
96
|
+
|
97
|
+
var post_data = {};
|
98
|
+
|
99
|
+
// Check that the password is valid
|
100
|
+
if(password_1 == '' || password_2 == '') {
|
101
|
+
// Show an error message
|
102
|
+
console.log('password is empty');
|
103
|
+
$('#user_password_error_message').text('Password cannot be empty');
|
104
|
+
$('#user_password_failure').removeClass('hidden');
|
105
|
+
|
106
|
+
return false;
|
107
|
+
} else if(password_1 != password_2) {
|
108
|
+
// Show an error message
|
109
|
+
console.log('passwords do not match');
|
110
|
+
$('#user_password_error_message').text('Passwords do not match');
|
111
|
+
$('#user_password_failure').removeClass('hidden');
|
112
|
+
|
113
|
+
return false;
|
114
|
+
} else {
|
115
|
+
post_data['new_password'] = password_1;
|
116
|
+
}
|
117
|
+
|
118
|
+
if(change_secret){
|
119
|
+
if( secret == '' ){
|
120
|
+
// Show an error message
|
121
|
+
console.log('secret is empty');
|
122
|
+
$('#user_password_error_message').text('Client token cannot be empty');
|
123
|
+
$('#user_password_failure').removeClass('hidden');
|
124
|
+
|
125
|
+
return false;
|
126
|
+
} else {
|
127
|
+
post_data['secret'] = secret;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
console.log(`url=${gblUserURL} data=${JSON.stringify(post_data)}`);
|
132
|
+
|
133
|
+
// Update the authentication details
|
134
|
+
api_put(gblUserURL, post_data, gblUsername, null, user_password_update_failed);
|
135
|
+
}
|
136
|
+
|
137
|
+
$(document).ready(function() {
|
138
|
+
$('#user_password_reset_signing').click(user_password_secret_toggle);
|
139
|
+
|
140
|
+
// Reset the password form every time it's opened
|
141
|
+
$('#user_password_modal').on('show.bs.modal', user_password_form_reset);
|
142
|
+
|
143
|
+
// Validate & submit the password form
|
144
|
+
$('#user_password_ok').click(user_password_validate_submit);
|
145
|
+
});
|