Changeset 490

Show
Ignore:
Timestamp:
08/01/07 15:08:34 (1 year ago)
Author:
brian
Message:

new publication schedule script, more work to be done for scheduled items especially

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pagoda/branches/cleanslate/Pagoda/pagoda/controllers/admin.py

    r479 r490  
    148148        # to hit the database once. 
    149149        select_revisions = approve | dismiss 
    150         for revision in query.select(revision_id.in_(*select_revisions)): 
    151             if revision.revision_id in approve: 
    152                 revision.revision_status = workflow.APPROVED 
    153             elif revision.revision_id in dismiss: 
    154                 revision.revision_status = workflow.PENDING 
    155          
    156         models.session.flush() 
    157         return dict(success=True) 
     150         
     151        transaction = models.session.create_transaction() 
     152        try: 
     153            revisions = query.select(revision_id.in_(*selection_revisions)) 
     154            for revision in revisions: 
     155                if revision.revision_id in approve: 
     156                    revision.revision_status = workflow.APPROVED 
     157                elif revision.revision_id in dismiss: 
     158                    revision.revision_status = workflow.DRAFT 
     159            transaction.commit() 
     160        except models.exceptions.SQLAlchemyError: 
     161            transaction.rollback() 
     162            result = dict(success=False) 
     163        else: 
     164            result = dict(success=True) 
     165         
     166        return result 
    158167     
    159168    @expose(format='json', allow_json=True) 
     
    180189        # to hit the database once. 
    181190        select_revisions = release | expire | cancel_release | cancel_expire 
    182         for revision in query.select(revision_id.in_(*select_revisions)): 
    183             if revision.revision_id in release: 
    184                 revision.revision_release_time = models.now 
    185             elif revision.revision_id in cancel_release: 
    186                 revision.revision_release_time = None 
    187             if revision.revision_id in expire: 
    188                 revision.revision_expire_time = models.now 
    189             elif revision.revision_id in cancel_expire: 
    190                 revision.revision_expire_time = None 
    191  
    192         models.session.flush() 
    193         return dict(success=True) 
     191         
     192        transaction = models.session.create_transaction() 
     193        try: 
     194            revisions = query.select(revision_id.in_(*select_revisions)) 
     195            for revision in revisions: 
     196                if revision.revision_id in release: 
     197                    revision.revision_release_time = models.now 
     198                elif revision.revision_id in cancel_release: 
     199                    revision.revision_release_time = None 
     200                if revision.revision_id in expire: 
     201                    revision.revision_expire_time = models.now 
     202                elif revision.revision_id in cancel_expire: 
     203                    revision.revision_expire_time = None         
     204            transaction.commit() 
     205        except models.exceptions.SQLAlchemyError: 
     206            transaction.rollback() 
     207            result = dict(success=False) 
     208        else: 
     209            result = dict(success=True) 
     210         
     211        return result 
    194212 
    195213class AccountsController(Controller, identity.SecureResource): 
  • pagoda/branches/cleanslate/Pagoda/pagoda/models/__init__.py

    r468 r490  
    11from turbogears.database import metadata, session 
     2from sqlalchemy import exceptions 
    23from pagoda.models.util import * 
    34from pagoda.models.identity import * 
  • pagoda/branches/cleanslate/Pagoda/pagoda/templates/admin/login.html

    r478 r490  
    2929        <input type="hidden" name="forward_url" value="${forward_url}"/> 
    3030        <input type="hidden" name="previous_url" value="${previous_url}"/> 
    31         <input py:for="name, value in original_parameters.items()" py:if="name not in ('forward_url', 'previous_url')" 
    32                type="hidden" name="${name}" value="${value}"/> 
     31        <py:for each="name, values in original_parameters.items()" py:if="name not in ('forward_url', 'previous_url')"> 
     32            <input py:for="value in isinstance(values, list) and values or [values]" 
     33                   type="hidden" name="${name}" value="${value}"/> 
     34        </py:for> 
    3335    </form> 
    3436</div> 
  • pagoda/branches/cleanslate/Pagoda/pagoda/templates/admin/schedule.html

    r479 r490  
    1616 
    1717<div id="body"> 
    18     <form id="pending" name="pending" action="pending" method="GET" class="schedule" 
     18    <form id="pending" name="pending" action="pending" method="POST" class="schedule" 
    1919          py:with="pending_count = len(pending_revisions)"> 
    2020        <h2>Pending Changes</h2> 
     
    2727        <div class="date-header" py:if="pending_revisions">submission date</div> 
    2828        <p class="actions-all" py:if="pending_revisions"> 
    29             <button type="button" name="approve" value="all" class="action-proceed" title="Approve all content&mdash;release it on the live site immediately or on its release date."> 
    30                 Approve all (${pending_count}
     29            <button type="button" name="approve" class="action-proceed" title="Approve all content&mdash;release it on the live site immediately or on its release date."> 
     30                Approve all (<span class="count approved">${pending_count}</span>
    3131            </button> 
    32             <button type="button" name="dismiss" value="all" class="action-cancel" title="Dismiss all content&mdash;send it back for editing. No changes will be lost."> 
    33                 Dismiss all (${pending_count}
     32            <button type="button" name="dismiss" class="action-cancel" title="Dismiss all content&mdash;send it back for editing. No changes will be lost."> 
     33                Dismiss all (<span class="count dismissed">${pending_count}</span>
    3434            </button> 
    3535        </p> 
     
    8686        <div class="date-header" py:if="scheduled_revisions">scheduled date</div> 
    8787        <p class="actions-all" py:if="scheduled_revisions"> 
    88             <button type="button" class="action-proceed" py:if="releasing_revisions" title="Immediately release all content scheduled to be released below."> 
     88            <button type="button" name="release" class="action-proceed" py:if="releasing_revisions" title="Immediately release all content scheduled to be released below."> 
    8989                Release all now (${releasing_count}) 
    9090            </button> 
    91             <button type="button" class="action-proceed" py:if="expiring_revisions" title="Immediately expire all content scheduled to expire below."> 
     91            <button type="button" name="expire" class="action-proceed" py:if="expiring_revisions" title="Immediately expire all content scheduled to expire below."> 
    9292                Expire all now (${expiring_count}) 
    9393            </button> 
    94             <button type="button" class="action-cancel" title="Cancel all releases and expirations."> 
     94            <button type="button" name="cancel" class="action-cancel" title="Cancel all releases and expirations."> 
    9595                Cancel all (${scheduled_count}) 
    9696            </button> 
     
    114114                    </p> 
    115115                    <p class="details"> 
    116                         <strong py:choose="revision.was_previously_approved()"> 
    117                             <span py:when="True">revised</span> 
    118                             <span py:when="False">new</span> 
     116                        <strong py:choose="is_expiration, revision.was_previously_approved()"> 
     117                            <span py:when="True, True">live</span> 
     118                            <span py:when="True, False">live</span> 
     119                            <span py:when="False, True">revised</span> 
     120                            <span py:when="False, False">new</span> 
    119121                            ${revision.content_type} 
    120122                        </strong> by ${revision.author.user_name} 
     
    125127                    <p class="actions" py:choose="is_expiration"> 
    126128                        <span py:when="0" py:strip=""> 
    127                             <button type="button" class="action-proceed" title="Release this content&mdash;make it available on the live site immediately."> 
     129                            <button type="button" name="release" value="${revision.revision_id}" class="action-proceed" title="Release this content&mdash;make it available on the live site immediately."> 
    128130                                Release now 
    129131                            </button> 
    130                             <button type="button" class="action-cancel" title="Cancel this release&mdash;undo approval and send the content back for editing."> 
     132                            <button type="button" name="cancel_release" value="${revision.revision_id}" class="action-cancel" title="Cancel this release&mdash;undo approval and send the content back for editing."> 
    131133                                Cancel release 
    132134                            </button> 
    133135                        </span> 
    134136                        <span py:when="1" py:strip=""> 
    135                             <button type="button" class="action-proceed" title="Expire this content&mdash;remove it from the live site immediately."> 
     137                            <button type="button" name="expire" value="${revision.revision_id}" class="action-proceed" title="Expire this content&mdash;remove it from the live site immediately."> 
    136138                                Expire now 
    137139                            </button> 
    138                             <button type="button" class="action-cancel" title="Cancel this expiration&mdash;keep the content on the live site until further action."> 
     140                            <button type="button" name="cancel_expire" value="${revision.revision_id}" class="action-cancel" title="Cancel this expiration&mdash;keep the content on the live site until further action."> 
    139141                                Cancel expiration 
    140142                            </button> 
  • pagoda/branches/cleanslate/Pagoda/pagoda/widgets/admin/static/css/schedule.css

    r479 r490  
    1111} 
    1212 
     13.schedule { 
     14    width: 50em; 
     15    margin: 0 auto; 
     16    padding: 2em; 
     17    background: #fff; 
     18    border: 1px solid #bbb; 
     19    text-align: left; 
     20} 
     21 
    1322.schedule .date-header, 
    1423.schedule .date-group { 
     
    1827    width: 11em; 
    1928    margin-left: -14em; 
     29    padding-right: 3em; 
    2030} 
    2131 
    2232.schedule .date-header { 
    23     padding-top: 2em; 
     33    padding-top: 2.5em; 
    2434    color: #888a85; 
    2535} 
     
    2939    margin-top: 0.5em; 
    3040    color: #555753; 
    31 } 
    32  
    33 .schedule { 
    34     width: 50em; 
    35     margin: 0 auto; 
    36     padding: 2em; 
    37     background: #fff; 
    38     border: 1px solid #bbb; 
    39     text-align: left; 
    4041} 
    4142 
     
    7071.schedule ul li.empty { 
    7172    text-align: center; 
     73} 
     74 
     75.schedule ul li.approved, 
     76.schedule ul li.dismissed { 
     77} 
     78 
     79.schedule ul li.approved .status, 
     80.schedule ul li.dismissed .status { 
     81    margin-bottom: 0; 
     82    font-weight: bold; 
     83} 
     84 
     85.schedule ul li.approved .title, 
     86.schedule ul li.dismissed .title { 
     87    font-size: 100%; 
     88} 
     89 
     90.schedule ul li.approved .details, 
     91.schedule ul li.dismissed .details { 
     92    display: none; 
     93} 
     94 
     95.schedule ul li.approved .actions, 
     96.schedule ul li.dismissed .actions { 
     97    display: none; 
    7298} 
    7399 
     
    109135} 
    110136 
     137.schedule button:disabled, 
     138.schedule button:disabled:hover, 
     139.schedule button:disabled:focus, 
     140.schedule button.disabled, 
     141.schedule button.disabled:hover, 
     142.schedule button.disabled:focus { 
     143    color: #bbb !important; 
     144    border-color: #ccc; 
     145} 
     146 
    111147.schedule button:hover, 
    112148.schedule button:focus, 
  • pagoda/branches/cleanslate/Pagoda/pagoda/widgets/admin/static/javascript/schedule.js

    r458 r490  
    1 // Ext.ObservableElement = function() { 
    2 //     // constructor 
    3 //     Ext.ObservableElement.superclass.constructor.call(this, arguments); 
    4 //     this.events = {}; 
    5 // } 
    6 //  
    7 // Ext.extend(Ext.ObservableElement, Ext.Element, {}); 
    8 // Ext.applyIf(Ext.ObservableElement.prototype, Ext.util.Observable.prototype); 
     1var clickSubmits = function(submitForm, clickSelector, itemSelector) { 
     2    submitForm.el.select(itemSelector).each(function() { 
     3        var item = this.dom || this; 
     4        this.select(clickSelector).each(function() { 
     5            var el = this.dom || this; 
     6            Ext.EventManager.addListener(this, 'click', function() { 
     7                var buttonParams = {}; 
     8                var items = {}; 
     9                items[el.name] = [item]; 
     10                buttonParams[el.name] = [el.value]; 
     11                submitForm.doAction('submitparams', {params: buttonParams, items: items}); 
     12            }); 
     13        }); 
     14 
     15    }); 
     16
     17 
     18var clickSubmitsAll = function(submitForm, clickSelector, valueSelector, itemSelector, itemFilters) { 
     19    var itemFilters = itemFilters || []; 
     20    submitForm.el.select(clickSelector).each(function() { 
     21        var el = this.dom || this; 
     22        Ext.EventManager.addListener(this, 'click', function() { 
     23            var allParams = {}; 
     24            var items = {}; 
     25            var selection = submitForm.el.select(itemSelector); 
     26            for (var i = 0; i < itemFilters.length; i++) { 
     27                selection = selection.filter(itemFilters[i]); 
     28            } 
     29            selection.each(function() { 
     30                var item = this.dom || this; 
     31                this.select(valueSelector).each(function() { 
     32                    var buttonEl = this.dom || this; 
     33                    if (allParams[buttonEl.name]) { 
     34                        allParams[buttonEl.name].push(buttonEl.value); 
     35                    } 
     36                    else { 
     37                        allParams[buttonEl.name] = [buttonEl.value]; 
     38                    } 
     39                    if (items[buttonEl.name]) { 
     40                        items[buttonEl.name].push(item); 
     41                    } 
     42                    else { 
     43                        items[buttonEl.name] = [item]; 
     44                    } 
     45                }); 
     46            }); 
     47            submitForm.doAction('submitparams', {params: allParams, items: items}); 
     48        }); 
     49    }); 
     50
     51 
     52var setupListSubmit = function(info) { 
     53    info.form.on('actioncomplete', info.success, info.form); 
     54    info.form.on('actionfailed', info.failure, info.form); 
     55     
     56    for (var name in info.one) { 
     57        clickSubmits(info.form, info.one[name], info.selector); 
     58    } 
     59    for (var name in info.all) { 
     60        clickSubmitsAll(info.form, info.all[name], info.one[name], info.selector, info.filters); 
     61    } 
     62
    963 
    1064Ext.onReady(function() { 
    11     var pendingForm = new Ext.form.BasicForm('pending'); 
    12      
    13     // var pendingForm = new Ext.ObservableElement('pending'); 
    14      
    15     pendingForm.on('submit', 
    16         function(button) { 
    17             var approveRevision = button.getValue(); 
    18             if (approveRevision == 'all') { 
    19                 console.log("Approving revisions..."); 
     65    var pendingForm = new Ext.BasicForm('pending'); 
     66    pendingForm.pagodaSetup = { 
     67        form: pendingForm, 
     68        selector: "ul li", 
     69        filters: [":not(.approved)", ":not(.dismissed)"], 
     70        one: {approve: ".actions button[name=approve]", dismiss: ".actions button[name=dismiss]"}, 
     71        all: {approve: ".actions-all button[name=approve]", dismiss: ".actions-all button[name=dismiss]"}, 
     72        status: {approve: "approved", dismiss: "dismissed"}, 
     73        cls: {approve: 'approved', dismiss: 'dismissed'}, 
     74        success: function(form, action) { 
     75            var processedCount = 0; 
     76            for (var name in action.options.items) { 
     77                var items = action.options.items[name] || []; 
     78                for (var i = 0; i < items.length; i++) { 
     79                    var el = Ext.get(items[i]); 
     80                    el.sequenceFx(); 
     81                    el.fadeOut({ 
     82                        duration: 0.25, 
     83                        afterCls: form.pagodaSetup.cls[name], 
     84                        scope: el, 
     85                        callback: function() { 
     86                            this.select('.status').update(form.pagodaSetup.status[name]); 
     87                        } 
     88                    }); 
     89                    el.fadeIn({ 
     90                        duration: 0.25, 
     91                        endOpacity: 0.5 
     92                    }); 
     93                } 
     94                processedCount += items.length; 
    2095            } 
    21             else { 
    22                 console.log("Approving revision ", approveRevision, "..."); 
     96             
     97            var approveCount = form.el.select('.count.approved'); 
     98            var dismissCount = form.el.select('.count.dismissed'); 
     99            var stillPendingCount = approveCount.first().dom.innerHTML - processedCount; 
     100            approveCount.update(stillPendingCount); 
     101            dismissCount.update(stillPendingCount); 
     102 
     103            if (!stillPendingCount) { 
     104                Ext.select(form.pagodaSetup.all.approve).set({disabled: true}); 
     105                Ext.select(form.pagodaSetup.all.dismiss).set({disabled: true}); 
    23106            } 
    24107        }, 
    25         pendingForm 
    26     ); 
    27     // var dismissAll = Ext.select('#pending .actions-all button.action-cancel'); 
    28     var approveButtons = Ext.select('#pending button.action-proceed'); 
    29     // var dismissButtons = Ext.select('#pending .actions button.action-cancel'); 
    30     approveButtons.on('click', 
    31         function(e) { 
    32             var button = Ext.get(this); 
    33             pendingForm.fireEvent('submit', button); 
     108        failure: function(form, action) { 
     109            console.log('ERROR!'); 
     110            console.log('form: ', form); 
     111            console.log('action: ', action); 
    34112        } 
    35     ); 
     113    }; 
     114    setupListSubmit(pendingForm.pagodaSetup); 
     115     
     116    var scheduledForm = new Ext.BasicForm('scheduled'); 
     117    scheduledForm.pagodaSetup = { 
     118        form: scheduledForm, 
     119        selector: "ul li", 
     120        filters: [":not(.released)", ":not(.expired)"], 
     121        one: { 
     122            release: ".actions button[name=release]", 
     123            expire: ".actions button[name=expire]", 
     124            cancel: ".actions button[name^=cancel]" 
     125        }, 
     126        all: { 
     127            release: ".actions-all button[name=release]", 
     128            expire: ".actions-all button[name=expire]", 
     129            cancel: ".actions-all button[name=cancel]" 
     130        }, 
     131        status: {release: "released", expire: "expired", cancel: "cancelled"}, 
     132        cls: {release: 'released', expire: 'expired', cancel: 'canceled'}, 
     133        success: function(form, action) { 
     134            console.log('SUCCESS!'); 
     135            console.log('form: ', form); 
     136            console.log('action: ', action); 
     137        }, 
     138        failure: function(form, action) { 
     139            console.log('ERROR!'); 
     140            console.log('form: ', form); 
     141            console.log('action: ', action); 
     142        } 
     143    }; 
     144    setupListSubmit(scheduledForm.pagodaSetup); 
    36145}); 
  • pagoda/branches/cleanslate/Pagoda/pagoda/widgets/admin/widgets.py

    r482 r490  
    5959schedule_base = JSLink( 
    6060    modname=module_name, filename='static/javascript/schedule.js', 
    61     css=[schedule_css], javascript=[admin_base
     61    css=[schedule_css], javascript=[admin_base, submit_params
    6262) 
    6363 

Log in as guest/pagoda to create tickets