<commit_before>;(function($, crud, win){
    var i18n = win.i18n;
    bind_events();
    $.widget("crud.crud_list", {
        options: {},
        _create: function()
        {

            var tbl = this.element;
            var order = [];

            var idx = 0;
            this.col_list = [];
            var obj = this;
            $("thead th", tbl).each(function(){
                var c = $(this);
                var col;

                col = {name: c.data('list_name'), data: c.data('list_data'), ctype: c.data('list_ctype')};

                col['orderable'] = c.data('list_orderable') == '1';
                if (obj.col_list.length == 0)
                {
                    if (c.data('list_ctype') === "checkbox")
                    {
                        col.fnCreatedCell = function(td, cellData, rowData, row, col){
                            $(td).html('<input data-widget="crud_checkbox" class="i-checks" data-rel="row" type="checkbox" value="' + cellData + '">').data('id',cellData)
                        }
                        //$('thead tr:first td:first',tbl).html('<input class="i-checks" type="checkbox">');
                    }
                    else
                    {
                        col.fnCreatedCell = function(td, cellData, rowData, row, col){
                            if (rowData['id'])
                            {
                                $(td).data('id',rowData['id']).attr('data-id', rowData['id']);
                            }
                            else
                            {
                                $(td).data('id',cellData).attr('data-id', cellData);
                            }
                        }
                    }
                }
                else
                {
                    col.fnCreatedCell = function(td, cellData, rowData, row, col){
                        $(td).attr('id', c.data('list_data')+'_'+rowData.id);
                    }

                    if (c.data('list_ctype') === "actions")
                    {

                        col.fnCreatedCell = function(td, cellData, rowData, row, col){
                            var buttons = '';

                            if (tbl.data('btn_edit'))
                            {
                                buttons += "    ";
                            }

                            if (tbl.data('btn_delete'))
                            {
                                buttons += " ";
                            }

                            if (tbl.data('list_actions')) {

                                var actions = tbl.data('list_actions');
                                buttons += ''
                                    + '<button class="btn btn-link dropdown-toggle" type="button"  data-toggle="dropdown">'
                                    + ''
                                    + '</button>'
                                    + '
';

                                for (var i=0; i<actions.length; i++)
                                {

                                    if (actions[i]['command'])
                                    {
                                        var com_url = crud.format_setting("model_command_url", {command:actions[i]['command'],id:rowData.id, model:tbl.data('crud_table'), scope:tbl.data('crud_scope')} );
                                        buttons += '
';
                                    } else if (actions[i]['event'])
                                    {
                                        buttons += '
';
                                    }
                                    else if (actions[i]['popup'])
                                    {
                                        buttons += '
';
                                    }

                                    if (actions[i]['class'])
                                    {
                                        buttons += ' ';
                                    }
                                    buttons += actions[i]['title']+'
';
                                    if (i<(actions.length-1))
                                    {
                                        buttons += '

';
                                    }
                                }

                                + '
'
                                + '';
                            }
                            $(td).html(buttons);
                        }

                    }
                }

                if (c.data('default_order'))
                {
                    order.push([idx,c.data('default_order')]);
                }

                idx ++;
                obj.col_list.push(col);
            });

            //console.log(cols);
            //var list_name = crud.crudObj.list_name ? crud.crudObj.list_name : 'index';
            var rowCallBack = crud.win.crudRowCallback ? crud.win.crudRowCallback : null;
            var dtConfig = {
                searching: tbl.data('searchable')?true:false,
                processing: true,
                serverSide: true,
                ajax: crud.format_setting("model_list_url", {model: tbl.data('crud_table'), scope: tbl.data('crud_scope'), uri_params: tbl.data('list_uri_params')}),
                //columns: crud_cols,
                order: order,
                autoWidth: false,
                columns: this.col_list,
                language: {
                    url: "/vendor/crud/js/i18n/vendor/dataTables/"+win.CURRENT_LOCALE+".json"
                },
                rowCallback: rowCallBack

            };

            if (tbl.data('list_type') == 'dt_tree')
            {

                dtConfig['processing'] = false;
                dtConfig['serverSide']  = false;
                dtConfig['ajax'] = {url:dtConfig['ajax'], data: {parent_id:0}};
                dtConfig['ordering'] =  false;
                dtConfig['paging'] =  false;
                dtConfig['treetable'] =  {
                    branchAttr: '__has_children',
                    nodeIdAttr: tbl.data('key_name'),
                    parentIdAttr: tbl.data('parent_id'),
                    expandable: true,
                        onNodeExpand: function() {
                            var node = this;
                            var url = tbl.DataTable().ajax.url();
                            var params = {parent_id:node.id, columns:tbl.DataTable().ajax.params()['columns']};
                            $.getJSON(url, params)
                                .done(function(json) {
                                    tbl.DataTable().treeTable.addChildren(node, json.data);
                                } )
                                .fail(function(e) {
                                    console.log("error", e);
                                } )
                        ;
                    }
                }
            }
            tbl.dataTable(dtConfig);

            tbl.on( 'draw.dt', function (e, o) {
                init_checkboxes(obj.col_list, this.element);
                crud.trigger('crud.content_loaded', {cont: $(e.target)});
            } );
            tbl.on('dblclick', 'tbody>tr', function (){

                if (tbl.data('crud_noedit') == '1')
                {
                    return;
                }
                //crud.trigger('crud.edit_element', {el:$(this).find('td').first()});
                crud.trigger('crud.edit_element', { id: $('td:first', $(this)).data('id'), table: tbl})
                //crud.init_modal($(this).find('td').first().data('id'));
            });
            if (tbl.data('form_type') == 'tabs')
            {
                var id = crud.loc.hash.substr(1);
                var model = tbl.data('crud_table') ? tbl.data('crud_table') : tbl.data('crud_tree');
                if (!isNaN(id) && id)
                {
                    crud.init_edit_tab(model, id, {table: tbl, scope: tbl.data('crud_scope')});
                }
            }
        }
    });

    function init_checkboxes(cols, cont)
    {
        if (cols[0]['ctype'] && cols[0]['ctype'] == 'checkbox')
        {
            var all_chck = $('<input data-widget="crud_checkbox" class="i-checks" type="checkbox">');
            all_chck.on('ifChecked', function ()
            {
                $('tr td', cont).find('input.i-checks').iCheck('check');
            });
            all_chck.on('ifUnchecked', function ()
            {
                $('tr td', cont).find('input.i-checks').iCheck('uncheck');
            });
            $('thead tr:first th:first', cont).removeClass('sorting_asc').html('').append(all_chck.clone(true));
            $('tfoot tr:first th:first', cont).html('').append(all_chck);
        }
        crud.trigger('form.init', {form: cont});
        //crud.init_ichecks();

    }

    function bind_events()
    {

        var crud_actions = {
            refresh_table: function (elem)
            {
                if (elem.data('ref'))
                {
                    $('table[data-list_table_ref='+elem.data('ref')+']').DataTable().ajax.reload();
                }
                else
                {
                    $('table[data-crud_table]').each(function(){
                        $(this).DataTable().ajax.reload();
                    });
                }
            },
            table_mass_delete: function(elem)
            {
                if (!elem.data('ref'))
                {
                    alert('No ref table provided');
                    return;
                }
                var tbl = $('table[data-list_table_ref='+elem.data('ref')+']');
                var ids = [];
                $('input[data-rel=row]', tbl).each(function(){
                    if ($(this).prop('checked'))
                    {
                        ids.push($(this).val());
                    }
                });
                if (ids.length <= 0)
                {
                    alert(i18n.say('no_item_selected'));
                    return;
                }
                if (confirm(i18n.say('delete_selected')+'?'))
                {
                    $.post(crud.format_setting('model_delete_url', {model: tbl.data('crud_table')}),{ids:ids}, function (res) {
                        crud.trigger('crud.delete',res);
                    })
                }

            }
        };
        crud.add_actions(crud_actions);

        crud.bind('crud.delete_element', function(data){

            if (data['id'])
            {
                var ids = [data['id']];
                if (data.table)
                {
                    data.table.find('td#id_'+data['id']).parent().remove();
                }
                $.post(crud.format_setting('model_delete_url', {model: data.crud_table}),{'ids':ids}, function (res) {
                    crud.trigger('crud.delete',res);
                })
            }
        });

        //
        crud.bind('crud.update', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload(null, false);
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        crud.bind('crud.reload', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload(null, false);
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        crud.bind('crud.filter_set', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload();
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        crud.bind('crud.delete', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload(null, false);
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        $(crud.doc).on('submit', '#crud_filter_form', function (e) {
            e.preventDefault();
            var $form = $(this);
            crud.trigger('form.before_submit', {form: $form});
            $form.ajaxSubmit(
                {
                    type:'POST',
                    url: crud.format_setting("model_filter_url", {model: $form.data('crud_model'), scope: $form.data('crud_scope')}),
                    //url: '/admin/crud/'+crud.crudObj['class_name']+'/filter/'+$(this).data('crud_context'),
                    dataType: 'json',
                    success: function (res) {
                        crud.trigger('form.after_submit', {form: $form});
                        //crud.toggle_form_progress($form)
                        crud.trigger('crud.filter_set', res);

                    }

                }
            );

        });

        $(crud.doc).on('reset', '#crud_filter_form', function (e) {
            //e.preventDefault();
            var $form = $(this);
            $('select', $form).each(function (){
                var val = null;
                if ($(this).data('default'))
                {
                    if ($(this).attr('multiple')) {
                        val = $(this).data('default').toString();
                        if (val) {

                            val = val.split(',');
                        }
                    } else {
                        val = $(this).data('default')
                    }
                }
                $(this).selectpicker("val", val);
            });

            $('input', $form).each(function (){
                $(this).val($(this).data('default'));
            });

            crud.trigger('form.before_submit', {form: $form});
            $form.ajaxSubmit(
                {
                    type:'POST',
                    url: crud.format_setting('model_filter_url', {model: $form.data('crud_model'), scope: $form.data('crud_scope')}),
                    //url: '/admin/crud/'+crud.crudObj['class_name']+'/filter/'+$(this).data('crud_context'),
                    dataType: 'json',
                    success: function (res) {
                        crud.trigger('form.after_submit', {form: $form});
                        //crud.toggle_form_progress($form)
                        crud.trigger('crud.filter_set',res);
                    }

                }
            );

        });

    }

})(jQuery, CRUD, window)<commit_msg>-- locks<commit_after>;(function($, crud, win){
    var i18n = win.i18n;
    bind_events();
    $.widget("crud.crud_list", {
        options: {},
        _create: function()
        {

            var tbl = this.element;
            var order = [];

            var idx = 0;
            this.col_list = [];
            var obj = this;
            $("thead th", tbl).each(function(){
                var c = $(this);
                var col;

                col = {name: c.data('list_name'), data: c.data('list_data'), ctype: c.data('list_ctype')};

                col['orderable'] = c.data('list_orderable') == '1';
                if (obj.col_list.length == 0)
                {
                    if (c.data('list_ctype') === "checkbox")
                    {
                        col.fnCreatedCell = function(td, cellData, rowData, row, col){
                            $(td).html('<input data-widget="crud_checkbox" class="i-checks" data-rel="row" type="checkbox" value="' + cellData + '">').data('id',cellData)
                        }
                        //$('thead tr:first td:first',tbl).html('<input class="i-checks" type="checkbox">');
                    }
                    else
                    {
                        col.fnCreatedCell = function(td, cellData, rowData, row, col){
                            if (rowData['id'])
                            {
                                $(td).data('id',rowData['id']).attr('data-id', rowData['id']);
                            }
                            else
                            {
                                $(td).data('id',cellData).attr('data-id', cellData);
                            }
                        }
                    }
                }
                else
                {
                    col.fnCreatedCell = function(td, cellData, rowData, row, col){
                        $(td).attr('id', c.data('list_data')+'_'+rowData.id);
                    }

                    if (c.data('list_ctype') === "actions")
                    {

                        col.fnCreatedCell = function(td, cellData, rowData, row, col){
                            var buttons = '';

                            if (tbl.data('btn_edit'))
                            {
                                buttons += "    ";
                            }

                            if (tbl.data('btn_delete'))
                            {
                                buttons += " ";
                            }

                            if (tbl.data('list_actions')) {

                                var actions = tbl.data('list_actions');
                                buttons += ''
                                    + '<button class="btn btn-link dropdown-toggle" type="button"  data-toggle="dropdown">'
                                    + ''
                                    + '</button>'
                                    + '
';

                                for (var i=0; i<actions.length; i++)
                                {

                                    if (actions[i]['command'])
                                    {
                                        var com_url = crud.format_setting("model_command_url", {command:actions[i]['command'],id:rowData.id, model:tbl.data('crud_table'), scope:tbl.data('crud_scope')} );
                                        buttons += '
';
                                    } else if (actions[i]['event'])
                                    {
                                        buttons += '
';
                                    }
                                    else if (actions[i]['popup'])
                                    {
                                        buttons += '
';
                                    }

                                    if (actions[i]['class'])
                                    {
                                        buttons += ' ';
                                    }
                                    buttons += actions[i]['title']+'
';
                                    if (i<(actions.length-1))
                                    {
                                        buttons += '

';
                                    }
                                }

                                + '
'
                                + '';
                            }
                            $(td).html(buttons);
                        }

                    }
                }

                if (c.data('default_order'))
                {
                    order.push([idx,c.data('default_order')]);
                }

                idx ++;
                obj.col_list.push(col);
            });

            //console.log(cols);
            //var list_name = crud.crudObj.list_name ? crud.crudObj.list_name : 'index';
            var rowCallBack = crud.win.crudRowCallback ? crud.win.crudRowCallback : null;
            var dtConfig = {
                searching: tbl.data('searchable')?true:false,
                processing: true,
                serverSide: true,
                ajax: crud.format_setting("model_list_url", {model: tbl.data('crud_table'), scope: tbl.data('crud_scope'), uri_params: tbl.data('list_uri_params')}),
                //columns: crud_cols,
                order: order,
                autoWidth: false,
                columns: this.col_list,
                language: {
                    url: "/vendor/crud/js/i18n/vendor/dataTables/"+win.CURRENT_LOCALE+".json"
                },
                rowCallback: rowCallBack

            };

            if (tbl.data('list_type') == 'dt_tree')
            {

                dtConfig['processing'] = false;
                dtConfig['serverSide']  = false;
                dtConfig['ajax'] = {url:dtConfig['ajax'], data: {parent_id:0}};
                dtConfig['ordering'] =  false;
                dtConfig['paging'] =  false;
                dtConfig['treetable'] =  {
                    branchAttr: '__has_children',
                    nodeIdAttr: tbl.data('key_name'),
                    parentIdAttr: tbl.data('parent_id'),
                    expandable: true,
                        onNodeExpand: function() {
                            var node = this;
                            var url = tbl.DataTable().ajax.url();
                            var params = {parent_id:node.id, columns:tbl.DataTable().ajax.params()['columns']};
                            $.getJSON(url, params)
                                .done(function(json) {
                                    tbl.DataTable().treeTable.addChildren(node, json.data);
                                } )
                                .fail(function(e) {
                                    console.log("error", e);
                                } )
                        ;
                    }
                }
            }
            tbl.dataTable(dtConfig);

            tbl.on( 'draw.dt', function (e, o) {
                init_checkboxes(obj.col_list, this.element);
                crud.trigger('crud.content_loaded', {cont: $(e.target)});
            } );
            tbl.on('dblclick', 'tbody>tr', function (){

                if (tbl.data('crud_noedit') == '1')
                {
                    return;
                }
                //crud.trigger('crud.edit_element', {el:$(this).find('td').first()});
                crud.trigger('crud.edit_element', { id: $('td:first', $(this)).data('id'), table: tbl})
                //crud.init_modal($(this).find('td').first().data('id'));
            });
            if (tbl.data('form_type') == 'tabs')
            {
                var id = crud.loc.hash.substr(1);
                var model = tbl.data('crud_table') ? tbl.data('crud_table') : tbl.data('crud_tree');
                if (!isNaN(id) && id)
                {
                    crud.init_edit_tab(model, id, {table: tbl, scope: tbl.data('crud_scope')});
                }
            }
        }
    });

    function init_checkboxes(cols, cont)
    {
        if (cols[0]['ctype'] && cols[0]['ctype'] == 'checkbox')
        {
            var all_chck = $('<input data-widget="crud_checkbox" class="i-checks" type="checkbox">');
            all_chck.on('ifChecked', function ()
            {
                $('tr td', cont).find('input.i-checks').iCheck('check');
            });
            all_chck.on('ifUnchecked', function ()
            {
                $('tr td', cont).find('input.i-checks').iCheck('uncheck');
            });
            $('thead tr:first th:first', cont).removeClass('sorting_asc').html('').append(all_chck.clone(true));
            $('tfoot tr:first th:first', cont).html('').append(all_chck);
        }
        crud.trigger('form.init', {form: cont});
        //crud.init_ichecks();

    }

    function bind_events()
    {

        var crud_actions = {
            refresh_table: function (elem)
            {
                if (elem.data('ref'))
                {
                    $('table[data-list_table_ref='+elem.data('ref')+']').DataTable().ajax.reload();
                }
                else
                {
                    $('table[data-crud_table]').each(function(){
                        $(this).DataTable().ajax.reload();
                    });
                }
            },
            table_mass_delete: function(elem)
            {
                if (!elem.data('ref'))
                {
                    alert('No ref table provided');
                    return;
                }
                var tbl = $('table[data-list_table_ref='+elem.data('ref')+']');
                var ids = [];
                $('input[data-rel=row]', tbl).each(function(){
                    if ($(this).prop('checked'))
                    {
                        ids.push($(this).val());
                    }
                });
                if (ids.length <= 0)
                {
                    alert(i18n.say('no_item_selected'));
                    return;
                }
                if (confirm(i18n.say('delete_selected')+'?'))
                {
                    $.post(crud.format_setting('model_delete_url', {model: tbl.data('crud_table')}),{ids:ids}, function (res) {
                        crud.trigger('crud.delete',res);
                    })
                }

            }
        };
        crud.add_actions(crud_actions);

        crud.bind('crud.delete_element', function(data){

            if (data['id'])
            {
                var ids = [data['id']];
                if (data.table)
                {
                    data.table.find('td#id_'+data['id']).parent().remove();
                }
                $.post(crud.format_setting('model_delete_url', {model: data.crud_table}),{'ids':ids}, function (res) {
                    crud.trigger('crud.delete',res);
                })
            }
        });

        //
        crud.bind('crud.update', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload(null, false);
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        crud.bind('crud.reload', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload(null, false);
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        crud.bind('crud.filter_set', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload();
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        crud.bind('crud.delete', function(res){
            if (res.success)
            {
                //$('.crud_table').DataTable().ajax.reload(null, false);
                $('table[data-crud_table]').DataTable().ajax.reload(null, false);
            }
        });

        $(crud.doc).on('submit', '#crud_filter_form', function (e) {
            e.preventDefault();
            var $form = $(this);
            crud.trigger('form.before_submit', {form: $form});
            $form.ajaxSubmit(
                {
                    type:'POST',
                    url: crud.format_setting("model_filter_url", {model: $form.data('crud_model'), scope: $form.data('crud_scope')}),
                    //url: '/admin/crud/'+crud.crudObj['class_name']+'/filter/'+$(this).data('crud_context'),
                    dataType: 'json',
                    success: function (res) {
                        crud.trigger('form.after_submit', {form: $form});
                        //crud.toggle_form_progress($form)
                        crud.trigger('crud.filter_set', res);

                    }

                }
            );

        });

        $(crud.doc).on('reset', '#crud_filter_form', function (e) {
            //e.preventDefault();
            var $form = $(this);
            $('select', $form).each(function (){
                var val = null;
                if ($(this).data('default'))
                {
                    if ($(this).attr('multiple')) {
                        val = $(this).data('default').toString();
                        if (val) {

                            val = val.split(',');
                        }
                    } else {
                        val = $(this).data('default')
                    }
                }
                $(this).selectpicker("val", val);
            });

            $('input', $form).each(function (){
                $(this).val($(this).data('default'));
            });

            crud.trigger('form.before_submit', {form: $form});
            $form.ajaxSubmit(
                {
                    type:'POST',
                    url: crud.format_setting('model_filter_url', {model: $form.data('crud_model'), scope: $form.data('crud_scope')}),
                    //url: '/admin/crud/'+crud.crudObj['class_name']+'/filter/'+$(this).data('crud_context'),
                    dataType: 'json',
                    success: function (res) {
                        crud.trigger('form.after_submit', {form: $form});
                        //crud.toggle_form_progress($form)
                        crud.trigger('crud.filter_set',res);
                    }

                }
            );

        });

    }

})(jQuery, CRUD, window)<|endoftext|>


<commit_before>/*! Kernel CI Dashboard | Licensed under the GNU GPL v3 (or later) */
require([
    'jquery',
    'utils/init',
    'utils/error',
    'utils/request',
    'utils/table',
    'utils/html',
    'utils/const',
    'tables/build',
    'utils/date'
], function($, init, e, r, table, html, appconst, buildt) {
    'use strict';
    var gBuildsTable,
        gBuildReqData,
        gDateRange,
        gPageLen,
        gSearchFilter;

    document.getElementById('li-build').setAttribute('class', 'active');

    gDateRange = appconst.MAX_DATE_RANGE;
    gPageLen = null;
    gSearchFilter = null;

    /**
     * Update the table with the new data.
     *
     * @param {object} response: The response from the previous request.
    **/
    function getMoreBuildsDone(response) {
        var results;

        results = response.result;
        if (results.length > 0) {
            gBuildsTable.addRows(results);
        }

        // Remove the loading banner when we get the last response.
        // Not the best solution since the last real response might come
        // before other requests depending on API time.
        if ((response.skip + response.limit) >= response.count) {
            html.removeChildrenByClass('table-process');
        }
    }

    /**
     * Get the other remaining build reports.
     * Triggered after the initial get request.
     *
     * @param {object} response: The response from the previous request.
    **/
    function getMoreBuilds(response) {
        var deferred,
            iNode,
            idx,
            resLen,
            resTotal,
            spanNode,
            totalReq;

        resTotal = response.count;
        resLen = response.result.length;

        if (resLen < resTotal) {
            // Add a small loading banner while we load more results.
            spanNode = document.createElement('span');

            iNode = document.createElement('i');
            iNode.className = 'fa fa-cog fa-spin';

            spanNode.appendChild(iNode);
            spanNode.insertAdjacentHTML('beforeend', ' ');
            spanNode.appendChild(
                document.createTextNode('loading more results'));
            spanNode.insertAdjacentHTML('beforeend', '…');

            html.replaceByClassNode('table-process', spanNode);

            totalReq = Math.floor(resTotal / appconst.MAX_QUERY_LIMIT);

            // Starting at 1 since we already got the first batch of results.
            for (idx = 1; idx <= totalReq; idx = idx + 1) {
                gBuildReqData.skip = appconst.MAX_QUERY_LIMIT * idx;
                deferred = r.get('/_ajax/build', gBuildReqData);
                $.when(deferred)
                    .done(getMoreBuildsDone);
            }
        }
    }

    function getBuildsFail() {
        html.removeElement('table-loading');
        html.replaceContent(
            document.getElementById('table-div'),
            html.errorDiv('Error loading data.'));
    }

    function getBuildsDone(response) {
        var columns,
            results,
            rowUrl;

        function _renderKernel(data, type, object) {
            return buildt.renderKernel(
                data, type, '/build/' + object.job + '/kernel/' + data + '/');
        }

        function _renderDetails(data, type, object) {
            return buildt.renderDetails(
                '/build/id/' + object._id.$oid + '/', type);
        }

        results = response.result;
        if (results.length === 0) {
            html.removeElement('table-loading');
            html.replaceContent(
                document.getElementById('table-div'),
                html.errorDiv('No data available'));
        } else {
            rowUrl = '/build/id/%(_id)s/';

            columns = [
                {
                    data: '_id',
                    visible: false,
                    searchable: false,
                    orderable: false
                },
                {
                    data: 'job',
                    title: 'Tree',
                    type: 'string',
                    className: 'tree-column',
                    render: buildt.renderTree
                },
                {
                    data: 'git_branch',
                    title: 'Branch',
                    type: 'string',
                    className: 'branch-column'
                },
                {
                    data: 'kernel',
                    title: 'Kernel',
                    type: 'string',
                    className: 'kernel-column',
                    render: _renderKernel
                },
                {
                    data: 'defconfig_full',
                    title: 'Defconfig',
                    type: 'string',
                    className: 'defconfig-column',
                    render: buildt.renderDefconfig
                },
                {
                    data: 'arch',
                    title: 'Arch.',
                    type: 'string',
                    className: 'arch-column'
                },
                {
                    data: 'created_on',
                    title: 'Date',
                    type: 'date',
                    className: 'date-column pull-center',
                    render: buildt.renderDate
                },
                {
                    data: 'status',
                    title: 'Status',
                    type: 'string',
                    className: 'pull-center',
                    render: buildt.renderStatus
                },
                {
                    data: 'job',
                    title: '',
                    type: 'string',
                    orderable: false,
                    searchable: false,
                    className: 'select-column pull-center',
                    render: _renderDetails
                }
            ];

            gBuildsTable
                .data(results)
                .columns(columns)
                .order([6, 'desc'])
                .languageLengthMenu('build reports per page')
                .noIdURL(true)
                .rowURL(rowUrl)
                .rowURLElements(['_id'])
                .draw();

            gBuildsTable
                .pageLen(gPageLen)
                .search(gSearchFilter);
        }
    }

    function getBuilds() {
        var deferred;

        deferred = r.get('/_ajax/build', gBuildReqData);
        $.when(deferred)
            .fail(e.error, getBuildsFail)
            .done(getBuildsDone, getMoreBuilds);
    }

    if (document.getElementById('search-filter') !== null) {
        gSearchFilter = document.getElementById('search-filter').value;
    }
    if (document.getElementById('page-len') !== null) {
        gPageLen = document.getElementById('page-len').value;
    }
    if (document.getElementById('date-range') !== null) {
        gDateRange = document.getElementById('date-range').value;
    }

    gBuildReqData = {
        sort: 'created_on',
        sort_order: -1,
        date_range: gDateRange,
        limit: appconst.MAX_QUERY_LIMIT,
        field: [
            '_id',
            'arch',
            'created_on',
            'defconfig_full',
            'git_branch',
            'job',
            'kernel',
            'status'
        ]
    };

    gBuildsTable = table({
        tableId: 'builds-table',
        tableLoadingDivId: 'table-loading',
        tableDivId: 'table-div'
    });
    getBuilds();

    init.hotkeys();
    init.tooltip();
});
<commit_msg>Add functions to the execution queue<commit_after>/*! Kernel CI Dashboard | Licensed under the GNU GPL v3 (or later) */
require([
    'jquery',
    'utils/init',
    'utils/error',
    'utils/request',
    'utils/table',
    'utils/html',
    'utils/const',
    'tables/build',
    'utils/date'
], function($, init, e, r, table, html, appconst, buildt) {
    'use strict';
    var gBuildsTable,
        gBuildReqData,
        gDateRange,
        gPageLen,
        gSearchFilter;

    document.getElementById('li-build').setAttribute('class', 'active');

    gDateRange = appconst.MAX_DATE_RANGE;
    gPageLen = null;
    gSearchFilter = null;

    /**
     * Update the table with the new data.
     *
     * @param {object} response: The response from the previous request.
    **/
    function getMoreBuildsDone(response) {
        var results;

        results = response.result;
        if (results.length > 0) {
            setTimeout(function() {
                gBuildsTable.addRows(results);
            }, 0);
        }

        // Remove the loading banner when we get the last response.
        // Not the best solution since the last real response might come
        // before other requests depending on API time.
        if ((response.skip + response.limit) >= response.count) {
            html.removeChildrenByClass('table-process');
        }
    }

    /**
     * Get the other remaining build reports.
     * Triggered after the initial get request.
     *
     * @param {object} response: The response from the previous request.
    **/
    function getMoreBuilds(response) {
        var deferred,
            iNode,
            idx,
            resLen,
            resTotal,
            spanNode,
            totalReq;

        resTotal = response.count;
        resLen = response.result.length;

        if (resLen < resTotal) {
            // Add a small loading banner while we load more results.
            spanNode = document.createElement('span');

            iNode = document.createElement('i');
            iNode.className = 'fa fa-cog fa-spin';

            spanNode.appendChild(iNode);
            spanNode.insertAdjacentHTML('beforeend', ' ');
            spanNode.appendChild(
                document.createTextNode('loading more results'));
            spanNode.insertAdjacentHTML('beforeend', '…');

            html.replaceByClassNode('table-process', spanNode);

            totalReq = Math.floor(resTotal / appconst.MAX_QUERY_LIMIT);

            // Starting at 1 since we already got the first batch of results.
            for (idx = 1; idx <= totalReq; idx = idx + 1) {
                gBuildReqData.skip = appconst.MAX_QUERY_LIMIT * idx;
                deferred = r.get('/_ajax/build', gBuildReqData);
                $.when(deferred)
                    .done(getMoreBuildsDone);
            }
        }
    }

    function getBuildsFail() {
        html.removeElement('table-loading');
        html.replaceContent(
            document.getElementById('table-div'),
            html.errorDiv('Error loading data.'));
    }

    function getBuildsDone(response) {
        var columns,
            results,
            rowUrl;

        function _renderKernel(data, type, object) {
            return buildt.renderKernel(
                data, type, '/build/' + object.job + '/kernel/' + data + '/');
        }

        function _renderDetails(data, type, object) {
            return buildt.renderDetails(
                '/build/id/' + object._id.$oid + '/', type);
        }

        results = response.result;
        if (results.length === 0) {
            html.removeElement('table-loading');
            html.replaceContent(
                document.getElementById('table-div'),
                html.errorDiv('No data available'));
        } else {
            rowUrl = '/build/id/%(_id)s/';

            columns = [
                {
                    data: '_id',
                    visible: false,
                    searchable: false,
                    orderable: false
                },
                {
                    data: 'job',
                    title: 'Tree',
                    type: 'string',
                    className: 'tree-column',
                    render: buildt.renderTree
                },
                {
                    data: 'git_branch',
                    title: 'Branch',
                    type: 'string',
                    className: 'branch-column'
                },
                {
                    data: 'kernel',
                    title: 'Kernel',
                    type: 'string',
                    className: 'kernel-column',
                    render: _renderKernel
                },
                {
                    data: 'defconfig_full',
                    title: 'Defconfig',
                    type: 'string',
                    className: 'defconfig-column',
                    render: buildt.renderDefconfig
                },
                {
                    data: 'arch',
                    title: 'Arch.',
                    type: 'string',
                    className: 'arch-column'
                },
                {
                    data: 'created_on',
                    title: 'Date',
                    type: 'date',
                    className: 'date-column pull-center',
                    render: buildt.renderDate
                },
                {
                    data: 'status',
                    title: 'Status',
                    type: 'string',
                    className: 'pull-center',
                    render: buildt.renderStatus
                },
                {
                    data: 'job',
                    title: '',
                    type: 'string',
                    orderable: false,
                    searchable: false,
                    className: 'select-column pull-center',
                    render: _renderDetails
                }
            ];

            gBuildsTable
                .data(results)
                .columns(columns)
                .order([6, 'desc'])
                .languageLengthMenu('build reports per page')
                .noIdURL(true)
                .rowURL(rowUrl)
                .rowURLElements(['_id'])
                .draw();

            gBuildsTable
                .pageLen(gPageLen)
                .search(gSearchFilter);
        }
    }

    function getBuilds() {
        var deferred;

        deferred = r.get('/_ajax/build', gBuildReqData);
        $.when(deferred)
            .fail(e.error, getBuildsFail)
            .done(getBuildsDone, getMoreBuilds);
    }

    if (document.getElementById('search-filter') !== null) {
        gSearchFilter = document.getElementById('search-filter').value;
    }
    if (document.getElementById('page-len') !== null) {
        gPageLen = document.getElementById('page-len').value;
    }
    if (document.getElementById('date-range') !== null) {
        gDateRange = document.getElementById('date-range').value;
    }

    gBuildReqData = {
        sort: 'created_on',
        sort_order: -1,
        date_range: gDateRange,
        limit: appconst.MAX_QUERY_LIMIT,
        field: [
            '_id',
            'arch',
            'created_on',
            'defconfig_full',
            'git_branch',
            'job',
            'kernel',
            'status'
        ]
    };

    gBuildsTable = table({
        tableId: 'builds-table',
        tableLoadingDivId: 'table-loading',
        tableDivId: 'table-div'
    });
    setTimeout(getBuilds, 0);

    init.hotkeys();
    init.tooltip();
});
<|endoftext|>


<commit_before>import _ from 'lodash'
import { load } from '../collection/load'
import { pickOptionForSerialize } from '../collection/util/calcQueryKey'
import { createStandalonePromise } from '../util/batcher'
import { isPreloadSkip, markPromise } from '../plug/httpFetcher'
import { _getCollection } from '../defineCollection'
import runHook from '../collection/util/runHook'

let requestNum = 0
const makeStoreRequest = type => ({ _id: `relay-${requestNum++}`, type })
const makeRequest = (collection, type, ...args) => ({
  ...makeStoreRequest(type),
  collectionName: collection.name,
  tag: `${collection.name}-${type}`,
  args,
})
const makeFindRequest = (collection, type, query, option) => makeRequest(collection, type, query, pickOptionForSerialize(option))

function createPromiseInTable(promiseTable, id, props) {
  const p = createStandalonePromise()
  _.defaults(p, props)

  // mark promise
  p
    .then(ret => {
      if (promiseTable[id] === p) delete promiseTable[id]
      return ret
    })
    .catch(err => {
      if (promiseTable[id] === p) delete promiseTable[id]
      return Promise.reject(err)
    })
  promiseTable[id] = p

  return p
}

export default function relayClient({ onMessage }) {
  const promises = {}

  const postToWorker = (request, option, self) => {
    // always mark local promise and return
    const p = createPromiseInTable(promises, request._id, request)

    Promise.resolve(onMessage(request, option, self)).then(result => {
      // if has result, means can resolve now, no need wait for onWorkerMessage
      if (result) return p.resolve(result)
    })

    return p
  }

  function doFetch(self, request, option) {
    const p = postToWorker(request, option, self).then(res => {
      const result = request.type === 'get' ? [res.result] : res.result
      if (self.mutatedAt >= res.workerMutatedAt) {
        // ignore result, and no load, no mutation
        return result
      }
      return load(self, result, option)
    })
    markPromise(self, request._id, p)
    return p
  }

  const isFetch = (self, option) => !(isPreloadSkip(self, option) || option.queryHit || option.allIdsHit)

  const relayPlugin = base => ({
    ...base,

    getHook(next, collection, id, option = {}) {
      const ret = runHook(base.getHook, next, collection, id, option)
      // if fetch once. always consider as allIdsHit and no re-fetch from relayWorker
      if (collection._byIdAts[id]) {
        option.allIdsHit = true
      }
      if (isFetch(collection, option)) doFetch(collection, makeFindRequest(collection, 'get', id, option), option)
      return ret
    },

    findHook(next, collection, query = {}, option = {}) {
      const ret = runHook(base.findHook, next, collection, query, option)
      // depend on queryHit & allIdsHit, so need to run AFTER base.find
      if (isFetch(collection, option)) doFetch(collection, makeFindRequest(collection, 'find', query, option), option)
      return ret
    },

    findAsyncHook(next, collection, query = {}, option = {}) {
      return doFetch(collection, makeFindRequest(collection, 'findAsync', query, option), option).then(() =>
        runHook(base.findAsyncHook, next, collection, query, option))
    },

    setAllHook(next, collection, change, option) {
      runHook(base.setAllHook, next, collection, change, option)
      const request = makeRequest(collection, 'setAll', change)
      const p = postToWorker(request, {}, collection)
      // NOTE worker: submit -> load -> onLoad -> onMessage; no need to load request.result in here
      //   .then(res => load(collection, res.result))

      // need to register promise to collection._fetchingPromises, so that can wait for submit
      return markPromise(collection, request._id, p)
    },
  })

  relayPlugin.onWorkerMessage = (store, message) => {
    if (!message) return

    // message is a request response
    const promise = promises[message._id]
    if (promise) {
      promise.resolve(message)
    }

    if (message.type === 'ready') {
      _.each(promises, p => {
        if (p.type === 'ready') p.resolve(message)
      })
    }

    // message is like a redux dispatch
    if (message.type === 'load') {
      const collection = _getCollection(store, message.collectionName)
      if (!collection) throw new Error('Cannot get collection in onWorkerMessage function', message)
      load(collection, message.data)
    }
  }

  relayPlugin.ready = () => {
    const firstPromise = postToWorker(makeStoreRequest('ready'))

    let polling = setInterval(() => {
      if (polling) postToWorker(makeStoreRequest('ready'))
    }, 5000)

    return firstPromise.then(() => {
      clearInterval(polling)
      polling = false
    })
  }

  return relayPlugin
}
<commit_msg>fix: more likely to solve all ready promises<commit_after>import _ from 'lodash'
import { load } from '../collection/load'
import { pickOptionForSerialize } from '../collection/util/calcQueryKey'
import { createStandalonePromise } from '../util/batcher'
import { isPreloadSkip, markPromise } from '../plug/httpFetcher'
import { _getCollection } from '../defineCollection'
import runHook from '../collection/util/runHook'

let requestNum = 0
const makeStoreRequest = type => ({ _id: `relay-${requestNum++}`, type })
const makeRequest = (collection, type, ...args) => ({
  ...makeStoreRequest(type),
  collectionName: collection.name,
  tag: `${collection.name}-${type}`,
  args,
})
const makeFindRequest = (collection, type, query, option) => makeRequest(collection, type, query, pickOptionForSerialize(option))

function createPromiseInTable(promiseTable, id, props) {
  const p = createStandalonePromise()
  _.defaults(p, props)

  // mark promise
  p
    .then(ret => {
      if (promiseTable[id] === p) delete promiseTable[id]
      return ret
    })
    .catch(err => {
      if (promiseTable[id] === p) delete promiseTable[id]
      return Promise.reject(err)
    })
  promiseTable[id] = p

  return p
}

export default function relayClient({ onMessage }) {
  const promises = {}

  const postToWorker = (request, option, self) => {
    // always mark local promise and return
    const p = createPromiseInTable(promises, request._id, request)

    Promise.resolve(onMessage(request, option, self)).then(result => {
      // if has result, means can resolve now, no need wait for onWorkerMessage
      if (result) return p.resolve(result)
    })

    return p
  }

  function doFetch(self, request, option) {
    const p = postToWorker(request, option, self).then(res => {
      const result = request.type === 'get' ? [res.result] : res.result
      if (self.mutatedAt >= res.workerMutatedAt) {
        // ignore result, and no load, no mutation
        return result
      }
      return load(self, result, option)
    })
    markPromise(self, request._id, p)
    return p
  }

  const isFetch = (self, option) => !(isPreloadSkip(self, option) || option.queryHit || option.allIdsHit)

  const relayPlugin = base => ({
    ...base,

    getHook(next, collection, id, option = {}) {
      const ret = runHook(base.getHook, next, collection, id, option)
      // if fetch once. always consider as allIdsHit and no re-fetch from relayWorker
      if (collection._byIdAts[id]) {
        option.allIdsHit = true
      }
      if (isFetch(collection, option)) doFetch(collection, makeFindRequest(collection, 'get', id, option), option)
      return ret
    },

    findHook(next, collection, query = {}, option = {}) {
      const ret = runHook(base.findHook, next, collection, query, option)
      // depend on queryHit & allIdsHit, so need to run AFTER base.find
      if (isFetch(collection, option)) doFetch(collection, makeFindRequest(collection, 'find', query, option), option)
      return ret
    },

    findAsyncHook(next, collection, query = {}, option = {}) {
      return doFetch(collection, makeFindRequest(collection, 'findAsync', query, option), option).then(() =>
        runHook(base.findAsyncHook, next, collection, query, option))
    },

    setAllHook(next, collection, change, option) {
      runHook(base.setAllHook, next, collection, change, option)
      const request = makeRequest(collection, 'setAll', change)
      const p = postToWorker(request, {}, collection)
      // NOTE worker: submit -> load -> onLoad -> onMessage; no need to load request.result in here
      //   .then(res => load(collection, res.result))

      // need to register promise to collection._fetchingPromises, so that can wait for submit
      return markPromise(collection, request._id, p)
    },
  })

  relayPlugin.onWorkerMessage = (store, message) => {
    if (!message) return

    // any message also means ready
    _.each(promises, p => {
      if (p.type === 'ready') {
        // console.log('>>> relayClient resolve all ready', p._id)
        p.resolve(message)
      }
    })

    // message is a request response
    const promise = promises[message._id]
    if (promise) {
      promise.resolve(message)
    }

    // message is like a redux dispatch
    if (message.type === 'load') {
      const collection = _getCollection(store, message.collectionName)
      if (!collection) throw new Error('Cannot get collection in onWorkerMessage function', message)
      load(collection, message.data)
    }
  }

  relayPlugin.ready = () => {
    const firstPromise = postToWorker(makeStoreRequest('ready'))

    let polling = setInterval(() => {
      if (polling) {
        // console.log('>>> relayClient polling')
        postToWorker(makeStoreRequest('ready'))
      }
    }, 5000)

    return firstPromise.then(() => {
      clearInterval(polling)
      polling = false
    })
  }

  return relayPlugin
}
<|endoftext|>


<commit_before>Ext.namespace("GeoNode");
GeoNode.PermissionsEditor = Ext.extend(Ext.util.Observable, {
    // how do we determine permissions for viewing? one of:
    // ANYONE - all users can view
    // REGISTERED - all logged-in users can view
    // EDITORS - all users in the editor list can view
    viewMode: 'EDITORS',

    // how do we determine permissions for editing? one of:
    // REGISTERED - all logged-in users can edit
    // EDITORS - all users in the editor list can view
    editMode: 'LIST',

    // a Store with the users that have editor permission
    editors: null,

    // a GeoNode.UserSelector widget for the editor list
    editorChooser: null,

    // a Store with the users that have manager permission
    managers: null,

    // a GeoNode.UserSelector widget for the manager list
    managerChooser: null,

    constructor: function(config) {
        Ext.apply(this, config);
        this.addEvents({ 'updated': true });
        GeoNode.PermissionsEditor.superclass.constructor.call(this, config);
        this.initStores();
        this.readPermissions(config.permissions);
        this.doLayout();
    },

    initStores: function(config) {
        var notifyOfUpdate = (function(t) {
            return function() { return t.fireEvent("updated", t); }
        })(this);
        this.editors = new Ext.data.Store({
            reader: new Ext.data.JsonReader({
                root: 'users',
                totalProperty: 'count',
                fields: [{name: 'username'}]
            }),
            listeners: {
                add: notifyOfUpdate,
                remove: notifyOfUpdate,
                update: notifyOfUpdate
            }
        });
        this.managers = new Ext.data.Store({
            reader: new Ext.data.JsonReader({
                root: 'users',
                totalProperty: 'count',
                fields: [{name: 'username'}]
            }),
            listeners: {
                add: notifyOfUpdate,
                remove: notifyOfUpdate,
                update: notifyOfUpdate
            }
        });
    },

    buildUserChooser: function(cfg) {
        var finalConfig = { owner: this.permissions.owner, userLookup: this.userLookup };
        Ext.apply(finalConfig, cfg);

        return new GeoNode.UserSelector(finalConfig);
    },

    buildViewPermissionChooser: function() {
        return new Ext.Panel({
            border: false,
            bwrapCfg: { tag: 'p' },
            items: [
                {html: "" + gettext("Who can view and download this data?") + "", flex: 1, border: false},
                { xtype: 'radiogroup', columns: 1, value: this.viewMode, items: [
                    { xtype: 'radio', name: 'viewmode', inputValue: 'ANYONE', boxLabel: gettext( 'Anyone')},
                    { xtype: 'radio', name: 'viewmode', inputValue: 'REGISTERED', boxLabel: gettext('Any registered user')},
                    { xtype: 'radio', name: 'viewmode', inputValue: 'EDITORS', boxLabel: gettext('Only users who can edit')}
                ], listeners: {
                    change: function(grp, checked) {
                        this.viewMode = checked.inputValue;
                        this.fireEvent("updated", this);
                    },
                    scope: this
                }},
            ]
        });
    },

    buildEditPermissionChooser: function() {
        this.editorChooser = this.buildUserChooser({
            store: this.editors,
            availableUserConfig: {
                listeners: {
                    load: function(store, recs, opts) {
                        store.filterBy(function(rec) {
                            return this.editors.findExact("username", rec.get("username")) == -1
                                && this.managers.findExact("username", rec.get("username")) == -1;
                        }, this);
                    },
                    scope: this
                }
            }
        });

        this.editorChooser.setDisabled(this.editMode !== 'LIST');

        return new Ext.Panel({
            border: false,
            bwrapCfg: { tag: 'p' },
            items: [
                {html: "" +  gettext('Who can edit this data?') + "", flex: 1, border: false},
                { xtype: 'radiogroup', columns: 1, value: this.editMode, items: [
                    { xtype: 'radio', name: 'editmode', inputValue: 'REGISTERED', boxLabel: gettext('Any registered user')},
                    { xtype: 'radio', name: 'editmode', inputValue: 'LIST', boxLabel: gettext('Only the following users or groups:')}
                ], listeners: {
                    change: function(grp, checked) {
                        this.editMode = checked.inputValue;
                        this.editorChooser.setDisabled(this.editMode !== 'LIST');
                        this.fireEvent("updated", this);
                    },
                    scope: this
                }},
                this.editorChooser.panel
            ]
        });
    },

    buildManagePermissionChooser: function() {
        this.managerChooser = this.buildUserChooser({
            store: this.managers,
            availableUserConfig: {
                listeners: {
                    load: function(store, recs, opts) {
                        store.filterBy(function(rec) {
                            return this.editors.findExact("username", rec.get("username")) == -1
                                && this.managers.findExact("username", rec.get("username")) == -1;
                        }, this);
                    },
                    scope: this
                }
            }
        });
        return new Ext.Panel({
            border: false,
            bwrapCfg: { tag: 'p' },
            items: [
                {html: "" +  gettext('Who can manage and edit this data?') + "", flex: 1, border: false},
                this.managerChooser.panel
            ]
        });
    },

    readPermissions: function(json) {
        this.editors.suspendEvents();
        this.managers.suspendEvents();
        if (json['authenticated'] == 'layer_readwrite') {
            this.editMode = 'REGISTERED';
        } else if (json['authenticated'] == 'layer_readonly') {
            this.viewMode = 'REGISTERED';
        }

        if (json['anonymous'] == 'layer_readonly') {
            this.viewMode = 'ANYONE';
        }

        for (var i = 0; i < json.users.length; i++) {
            if (json.users[i][1] === 'layer_readwrite') {
                this.editors.add(new this.editors.recordType({username: json.users[i][0]}, i + 500));
            } else if (json.users[i][1] === 'layer_admin') {
                this.managers.add(new this.managers.recordType({username: json.users[i][0]}, i + 500));
            }
        }

        this.editors.resumeEvents();
        this.managers.resumeEvents();
    },

    // write out permissions to a JSON string, suitable for sending back to the mothership
    writePermissions: function() {
        var anonymousPermissions, authenticatedPermissions, perUserPermissions;
        if (this.viewMode === 'ANYONE') {
            anonymousPermissions = 'layer_readonly';
        } else {
            anonymousPermissions = '_none';
        }

        if (this.editMode === 'REGISTERED') {
            authenticatedPermissions = 'layer_readwrite';
        } else if (this.viewMode === 'REGISTERED') {
            authenticatedPermissions = 'layer_readonly';
        } else {
            authenticatedPermissions = '_none';
        }

        perUserPermissions = [];
        if (this.editMode === 'LIST') {
            this.editors.each(function(rec) {
                perUserPermissions.push([rec.get("username"), 'layer_readwrite']);
            });
        }

        this.managers.each(function(rec) {
            perUserPermissions.push([rec.get("username"), 'layer_admin']);
        });

        return {
            anonymous: anonymousPermissions,
            authenticated: authenticatedPermissions,
            users: perUserPermissions
        };
    },

    doLayout: function() {
        this.container = new Ext.Panel({
            renderTo: this.renderTo,
            border: false,
            items: [
                this.buildViewPermissionChooser(),
                this.buildEditPermissionChooser(),
                this.buildManagePermissionChooser()
            ]
        });
    }
});
<commit_msg>Make permission values configurable<commit_after>Ext.namespace("GeoNode");
GeoNode.PermissionsEditor = Ext.extend(Ext.util.Observable, {
    // how do we determine permissions for viewing? one of:
    // ANYONE - all users can view
    // REGISTERED - all logged-in users can view
    // EDITORS - all users in the editor list can view
    viewMode: 'EDITORS',

    // how do we determine permissions for editing? one of:
    // REGISTERED - all logged-in users can edit
    // EDITORS - all users in the editor list can view
    editMode: 'LIST',

    // a Store with the users that have editor permission
    editors: null,

    // a GeoNode.UserSelector widget for the editor list
    editorChooser: null,

    // a Store with the users that have manager permission
    managers: null,

    // a GeoNode.UserSelector widget for the manager list
    managerChooser: null,

    levels: {
        'admin': 'layer_admin',
        'readwrite': 'layer_readwrite',
        'readonly': 'layer_readonly',
        'none': '_none'
    },

    constructor: function(config) {
        Ext.apply(this, config);
        this.addEvents({ 'updated': true });
        GeoNode.PermissionsEditor.superclass.constructor.call(this, config);
        this.initStores();
        this.readPermissions(config.permissions);
        this.doLayout();
    },

    initStores: function(config) {
        var notifyOfUpdate = (function(t) {
            return function() { return t.fireEvent("updated", t); }
        })(this);
        this.editors = new Ext.data.Store({
            reader: new Ext.data.JsonReader({
                root: 'users',
                totalProperty: 'count',
                fields: [{name: 'username'}]
            }),
            listeners: {
                add: notifyOfUpdate,
                remove: notifyOfUpdate,
                update: notifyOfUpdate
            }
        });
        this.managers = new Ext.data.Store({
            reader: new Ext.data.JsonReader({
                root: 'users',
                totalProperty: 'count',
                fields: [{name: 'username'}]
            }),
            listeners: {
                add: notifyOfUpdate,
                remove: notifyOfUpdate,
                update: notifyOfUpdate
            }
        });
    },

    buildUserChooser: function(cfg) {
        var finalConfig = { owner: this.permissions.owner, userLookup: this.userLookup };
        Ext.apply(finalConfig, cfg);

        return new GeoNode.UserSelector(finalConfig);
    },

    buildViewPermissionChooser: function() {
        return new Ext.Panel({
            border: false,
            bwrapCfg: { tag: 'p' },
            items: [
                {html: "" + gettext("Who can view and download this data?") + "", flex: 1, border: false},
                { xtype: 'radiogroup', columns: 1, value: this.viewMode, items: [
                    { xtype: 'radio', name: 'viewmode', inputValue: 'ANYONE', boxLabel: gettext( 'Anyone')},
                    { xtype: 'radio', name: 'viewmode', inputValue: 'REGISTERED', boxLabel: gettext('Any registered user')},
                    { xtype: 'radio', name: 'viewmode', inputValue: 'EDITORS', boxLabel: gettext('Only users who can edit')}
                ], listeners: {
                    change: function(grp, checked) {
                        this.viewMode = checked.inputValue;
                        this.fireEvent("updated", this);
                    },
                    scope: this
                }},
            ]
        });
    },

    buildEditPermissionChooser: function() {
        this.editorChooser = this.buildUserChooser({
            store: this.editors,
            availableUserConfig: {
                listeners: {
                    load: function(store, recs, opts) {
                        store.filterBy(function(rec) {
                            return this.editors.findExact("username", rec.get("username")) == -1
                                && this.managers.findExact("username", rec.get("username")) == -1;
                        }, this);
                    },
                    scope: this
                }
            }
        });

        this.editorChooser.setDisabled(this.editMode !== 'LIST');

        return new Ext.Panel({
            border: false,
            bwrapCfg: { tag: 'p' },
            items: [
                {html: "" +  gettext('Who can edit this data?') + "", flex: 1, border: false},
                { xtype: 'radiogroup', columns: 1, value: this.editMode, items: [
                    { xtype: 'radio', name: 'editmode', inputValue: 'REGISTERED', boxLabel: gettext('Any registered user')},
                    { xtype: 'radio', name: 'editmode', inputValue: 'LIST', boxLabel: gettext('Only the following users or groups:')}
                ], listeners: {
                    change: function(grp, checked) {
                        this.editMode = checked.inputValue;
                        this.editorChooser.setDisabled(this.editMode !== 'LIST');
                        this.fireEvent("updated", this);
                    },
                    scope: this
                }},
                this.editorChooser.panel
            ]
        });
    },

    buildManagePermissionChooser: function() {
        this.managerChooser = this.buildUserChooser({
            store: this.managers,
            availableUserConfig: {
                listeners: {
                    load: function(store, recs, opts) {
                        store.filterBy(function(rec) {
                            return this.editors.findExact("username", rec.get("username")) == -1
                                && this.managers.findExact("username", rec.get("username")) == -1;
                        }, this);
                    },
                    scope: this
                }
            }
        });
        return new Ext.Panel({
            border: false,
            bwrapCfg: { tag: 'p' },
            items: [
                {html: "" +  gettext('Who can manage and edit this data?') + "", flex: 1, border: false},
                this.managerChooser.panel
            ]
        });
    },

    readPermissions: function(json) {
        this.editors.suspendEvents();
        this.managers.suspendEvents();
        if (json['authenticated'] == this.levels['readwrite']) {
            this.editMode = 'REGISTERED';
        } else if (json['authenticated'] == this.levels['readonly']) {
            this.viewMode = 'REGISTERED';
        }

        if (json['anonymous'] == this.levels['readonly']) {
            this.viewMode = 'ANYONE';
        }

        for (var i = 0; i < json.users.length; i++) {
            if (json.users[i][1] === this.levels['readwrite']) {
                this.editors.add(new this.editors.recordType({username: json.users[i][0]}, i + 500));
            } else if (json.users[i][1] === this.levels['admin']) {
                this.managers.add(new this.managers.recordType({username: json.users[i][0]}, i + 500));
            }
        }

        this.editors.resumeEvents();
        this.managers.resumeEvents();
    },

    // write out permissions to a JSON string, suitable for sending back to the mothership
    writePermissions: function() {
        var anonymousPermissions, authenticatedPermissions, perUserPermissions;
        if (this.viewMode === 'ANYONE') {
            anonymousPermissions = this.levels['readonly'];
        } else {
            anonymousPermissions = this.levels['_none'];
        }

        if (this.editMode === 'REGISTERED') {
            authenticatedPermissions = this.levels['readwrite'];
        } else if (this.viewMode === 'REGISTERED') {
            authenticatedPermissions = this.levels['readonly'];
        } else {
            authenticatedPermissions = this.levels['_none'];
        }

        perUserPermissions = [];
        if (this.editMode === 'LIST') {
            this.editors.each(function(rec) {
                perUserPermissions.push([rec.get("username"), this.levels['readwrite']]);
            }, this);
        }

        this.managers.each(function(rec) {
            perUserPermissions.push([rec.get("username"), this.levels['admin']]);
        }, this);

        return {
            anonymous: anonymousPermissions,
            authenticated: authenticatedPermissions,
            users: perUserPermissions
        };
    },

    doLayout: function() {
        this.container = new Ext.Panel({
            renderTo: this.renderTo,
            border: false,
            items: [
                this.buildViewPermissionChooser(),
                this.buildEditPermissionChooser(),
                this.buildManagePermissionChooser()
            ]
        });
    }
});
<|endoftext|>


<commit_before>'use strict';

// require your mailgun package
// Adding your key and domain to environment variables
// is important as you don’t want these values
// in your source control or otherwise exposed.
// process.env is an easy way to access your env variables
var   mongoose = require('mongoose'),
      User = mongoose.model('User'),
      mailgun_api = process.env.MAILGUN_API_KEY,
      mailgun_domain = process.env.MAILGUN_DOMAIN,
      Mailgun = require('mailgun-js'),
      Q = require('q'),
      //use nunjucks to render html templates w/ variables
      nunjucks = require('nunjucks');

// function to generate custom email
// for given users and return a mailing array
var mailCreator = function(users) {
  var mailing = [];

  for (var i = users.length - 1; i >= 0; i--) {
    // get an email template and pass in some variables
    var email = swig.renderFile('app/views/templates/email.inlined.template.html', {
      username: users[i].firstName
    });
    // add qualified users and their customized
    // email to the mailing
    mailing.push({
      user: users[i].email,
      email: email
    });
  }
  return mailing;
}

// function to send user email given template and subject
var mailSender = function (userEmail, subject, html) {
    // setup promises
    var deffered = Q.defer();
    // create new mailgun instance with credentials
    var mailgun = new Mailgun({
      apiKey: mailgun_api,
      domain: mailgun_domain
    });
    // setup the basic mail data
    var mailData = {
      from: 'you@yourdomain.com',
      to: userEmail,
      subject:  subject,
      html: html
    };
    // send your mailgun instance the mailData
    mailgun.messages().send(mailData, function (err, body) {
      // If err console.log so we can debug
      if (err) {
        deffered.reject(console.log('failed: ' + err));
      } else {
        deffered.resolve(body)
      }
    });

    return deffered.promise;
};

module.exports.mailSender = mailSender;
module.exports.mailCreator = mailCreator;
<commit_msg>remove swig reference<commit_after>'use strict';

// require your mailgun package
// Adding your key and domain to environment variables
// is important as you don’t want these values
// in your source control or otherwise exposed.
// process.env is an easy way to access your env variables
var   mongoose = require('mongoose'),
      User = mongoose.model('User'),
      mailgun_api = process.env.MAILGUN_API_KEY,
      mailgun_domain = process.env.MAILGUN_DOMAIN,
      Mailgun = require('mailgun-js'),
      Q = require('q'),
      //use nunjucks to render html templates w/ variables
      nunjucks = require('nunjucks');

// function to generate custom email
// for given users and return a mailing array
var mailCreator = function(users) {
  var mailing = [];

  for (var i = users.length - 1; i >= 0; i--) {
    // get an email template and pass in some variables
    var email = nunjucks.renderFile('app/views/templates/email.inlined.template.html', {
      username: users[i].firstName
    });
    // add qualified users and their customized
    // email to the mailing
    mailing.push({
      user: users[i].email,
      email: email
    });
  }

  return mailing;
}

// function to send user email given template and subject
var mailSender = function (userEmail, subject, html) {
    // setup promises
    var deffered = Q.defer();
    // create new mailgun instance with credentials
    var mailgun = new Mailgun({
      apiKey: mailgun_api,
      domain: mailgun_domain
    });
    // setup the basic mail data
    var mailData = {
      from: 'you@yourdomain.com',
      to: userEmail,
      subject:  subject,
      html: html
    };
    // send your mailgun instance the mailData
    mailgun.messages().send(mailData, function (err, body) {
      // If err console.log so we can debug
      if (err) {
        deffered.reject(console.log('failed: ' + err));
      } else {
        deffered.resolve(body)
      }
    });

    return deffered.promise;
};

module.exports.mailSender = mailSender;
module.exports.mailCreator = mailCreator;
<|endoftext|>


<commit_before>//	'ws' is a URL with a handler for all chat messages
var pathArray = window.location.pathname.split( '/' );
var ws = new WebSocket( 'ws://' + window.location.host + '/chat/' + pathArray[2] + '/send/' );

ws.onopen = function() {
	ws.send( JSON.stringify({
		type: "name",
		name: $( '#name' ).val(),
	}));
};

//	Starts off as the active window
var isActive = true;

//	Set as active window when focused
window.onfocus = function () {
  isActive = true;
};

//	Unset as active window when unfocused
window.onblur = function () {
  isActive = false;
};

//For up-down picking of previous messages
var sentMessages = [];
var sentMessagesIndex = -1;

//	when ws recieves a message, append some html with the contents of the message
ws.onmessage = function ( event ) {
	//Date calculation into local time
	var serverTimeString = JSON.parse(event.data).time + " GMT";
	var serverTime = new Date(serverTimeString);
	var localTimeString = serverTime.toLocaleTimeString( );

	//Function to derive the rand & nick hue from the randString
	function hueCalc( randString ) {
		var hueNum = 0;
		if ( randString ) {
			hueNum = Math.floor( randString.substr( 3, 5 ) * 359/999 );
		}
		return hueNum;
	}
	//Generate an HSL color from the randstring of this message
	var colorString = 'hsl(' + hueCalc( JSON.parse( event.data ).rand ) + ',60%,40%)';

	//	When a message is recieved, check the type of the message, and handle it accordingly
	switch ( JSON.parse(event.data).type ) {
		//	Server message format
		case "server":
			$( '#chatLog' ).append([
				'
',
					'[Server]: ' +
					'' + JSON.parse(event.data).text + '' ,
					'' + localTimeString + '',
				'
',
			].join( "\n" ));
		break;

		//	User message format
		case "user":
			//	If the user left their name blank:
			if ( JSON.parse(event.data).name === "" ) {
				$( '#chatLog' ).append([
					'
',
						'' + JSON.parse(event.data).rand + '' +
						'' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			//	If the user has a name:
			} else {
				$( '#chatLog' ).append([
					'
',
						''  + JSON.parse(event.data).rand + '' +
						''  + '[' + JSON.parse(event.data).name + ']: ' + '' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			};
		break;
		case "userList":
			$( '#nameList' ).val(
				//	JSON.parse(event.data).users is an array containing all of the names and IDs of users, formatted
				//	Your job is to put all of these inside of
s
			);
		break;
		case "keepalive":
			//	do nothing
		break;
		default:

		break;
	};

	//	this makes #chatLog scroll to the bottom after each new message
	$( '#chatLog' ).scrollTop( $( '#chatLog' )[0].scrollHeight );

	if ( !isActive && !!$('#notificationSounds').val() ) {
		document.getElementById('notificationTone').play();
	};
};

function websockSend(message) {

	//	If the outgoing message is blank, don't send
	if ( message == "" ) {
		return;
	};

	//	get a new date
	var date = new Date();
	//	send a JSON of name, text, and time (date) to ws
	ws.send( JSON.stringify({
		name: $( '#name' ).val(),
		text: message,
		time: date.toString(),
		type: "message",
	}));
	sentMessages.unshift( $( '#outgoing' ).val() );

	//	blank the outgoing message field
	$( '#outgoing' ).val( "" );
}

function getBacklog() {

}

//function to change the current message index without going too far in either direction
function changeMessageIndex(increment) {
	sentMessagesIndex += increment;

	if (sentMessagesIndex >= (sentMessages.length-1)) {
		sentMessagesIndex = sentMessages.length-1;
	}
	if (sentMessagesIndex <= 0) {
		sentMessagesIndex = 0;
	}
};

function toggleNameListVisibility(){

};

$( document ).ready(function() {
	$( '#outgoing' ).keyup( function( e ) {
		//	run a websockSend on a keypress of Enter (keycode 13)
		switch (e.which) {
			case 13:
				websockSend( $( '#outgoing' ).val() );
				sentMessagesIndex = -1;
				break;
			//	So up/down arrows cycle through message history
			case 38:
				changeMessageIndex(1);
				console.log("Current value of sentMessagesIndex is:",sentMessagesIndex);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
			case 40:
				changeMessageIndex(-1);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
		}
	});

	//	Run once on load
//	ws.send( JSON.stringify({
//		type: "name",
//		name: $( '#name' ).val(),
//	}));

	//	Then run again every time #name changes
	$( '#name' ).change( function() {
		ws.send( JSON.stringify({
			type: "name",
			name: $( '#name' ).val(),
		}));
	});

	//	Check if the server is alive every second (all clientside)
	var serverStatusCheck = setInterval( function() {
		if ( ws.readyState === undefined || ws.readyState > 1 ) {
			$( '#disconnectOverlay' ).fadeIn( 350 );
			clearInterval( serverStatusCheck );
			clearInterval( keepalivePing );
		}
	}, 1000 );

	//	Ping the server to keep your WS alive every 20 seconds
	var keepalivePing = setInterval( function() {
		ws.send(JSON.stringify({
			type: "keepalive",
		}));
	}, 20000 );
});
<commit_msg>Fixed making noises for userList messages<commit_after>//	'ws' is a URL with a handler for all chat messages
var pathArray = window.location.pathname.split( '/' );
var ws = new WebSocket( 'ws://' + window.location.host + '/chat/' + pathArray[2] + '/send/' );

ws.onopen = function() {
	ws.send( JSON.stringify({
		type: "name",
		name: $( '#name' ).val(),
	}));
};

//	Starts off as the active window
var isActive = true;

//	Set as active window when focused
window.onfocus = function () {
  isActive = true;
};

//	Unset as active window when unfocused
window.onblur = function () {
  isActive = false;
};

//For up-down picking of previous messages
var sentMessages = [];
var sentMessagesIndex = -1;

//	when ws recieves a message, append some html with the contents of the message
ws.onmessage = function ( event ) {
	//Date calculation into local time
	var serverTimeString = JSON.parse(event.data).time + " GMT";
	var serverTime = new Date(serverTimeString);
	var localTimeString = serverTime.toLocaleTimeString( );

	//Function to derive the rand & nick hue from the randString
	function hueCalc( randString ) {
		var hueNum = 0;
		if ( randString ) {
			hueNum = Math.floor( randString.substr( 3, 5 ) * 359/999 );
		}
		return hueNum;
	}
	//Generate an HSL color from the randstring of this message
	var colorString = 'hsl(' + hueCalc( JSON.parse( event.data ).rand ) + ',60%,40%)';

	//	When a message is recieved, check the type of the message, and handle it accordingly
	switch ( JSON.parse(event.data).type ) {
		//	Server message format
		case "server":
			$( '#chatLog' ).append([
				'
',
					'[Server]: ' +
					'' + JSON.parse(event.data).text + '' ,
					'' + localTimeString + '',
				'
',
			].join( "\n" ));

			//	Play notification sound
			if ( !isActive && !!$('#notificationSounds').val() ) {
				document.getElementById('notificationTone').play();
			};
		break;

		//	User message format
		case "user":
			//	If the user left their name blank:
			if ( JSON.parse(event.data).name === "" ) {
				$( '#chatLog' ).append([
					'
',
						'' + JSON.parse(event.data).rand + '' +
						'' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			//	If the user has a name:
			} else {
				$( '#chatLog' ).append([
					'
',
						''  + JSON.parse(event.data).rand + '' +
						''  + '[' + JSON.parse(event.data).name + ']: ' + '' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			};

			//	Play notification sound
			if ( !isActive && !!$('#notificationSounds').val() ) {
				document.getElementById('notificationTone').play();
			};
		break;
		case "userList":
			$( '#nameList' ).val(
				//	JSON.parse(event.data).users is an array containing all of the names and IDs of users, formatted
				//	Your job is to put all of these inside of
s
			);
		break;
		case "keepalive":
			//	do nothing
		break;
		default:

		break;
	};

	//	this makes #chatLog scroll to the bottom after each new message
	$( '#chatLog' ).scrollTop( $( '#chatLog' )[0].scrollHeight );
};

function websockSend(message) {

	//	If the outgoing message is blank, don't send
	if ( message == "" ) {
		return;
	};

	//	get a new date
	var date = new Date();
	//	send a JSON of name, text, and time (date) to ws
	ws.send( JSON.stringify({
		name: $( '#name' ).val(),
		text: message,
		time: date.toString(),
		type: "message",
	}));
	sentMessages.unshift( $( '#outgoing' ).val() );

	//	blank the outgoing message field
	$( '#outgoing' ).val( "" );
}

function getBacklog() {

}

//function to change the current message index without going too far in either direction
function changeMessageIndex(increment) {
	sentMessagesIndex += increment;

	if (sentMessagesIndex >= (sentMessages.length-1)) {
		sentMessagesIndex = sentMessages.length-1;
	}
	if (sentMessagesIndex <= 0) {
		sentMessagesIndex = 0;
	}
};

function toggleNameListVisibility(){

};

$( document ).ready(function() {
	$( '#outgoing' ).keyup( function( e ) {
		//	run a websockSend on a keypress of Enter (keycode 13)
		switch (e.which) {
			case 13:
				websockSend( $( '#outgoing' ).val() );
				sentMessagesIndex = -1;
				break;
			//	So up/down arrows cycle through message history
			case 38:
				changeMessageIndex(1);
				console.log("Current value of sentMessagesIndex is:",sentMessagesIndex);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
			case 40:
				changeMessageIndex(-1);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
		}
	});

	//	Run once on load
//	ws.send( JSON.stringify({
//		type: "name",
//		name: $( '#name' ).val(),
//	}));

	//	Then run again every time #name changes
	$( '#name' ).change( function() {
		ws.send( JSON.stringify({
			type: "name",
			name: $( '#name' ).val(),
		}));
	});

	//	Check if the server is alive every second (all clientside)
	var serverStatusCheck = setInterval( function() {
		if ( ws.readyState === undefined || ws.readyState > 1 ) {
			$( '#disconnectOverlay' ).fadeIn( 350 );
			clearInterval( serverStatusCheck );
			clearInterval( keepalivePing );
		}
	}, 1000 );

	//	Ping the server to keep your WS alive every 20 seconds
	var keepalivePing = setInterval( function() {
		ws.send(JSON.stringify({
			type: "keepalive",
		}));
	}, 20000 );
});
<|endoftext|>