Pages can now be deleted. Pages have a 'published' attribute that determines whether they are publicly accessible. There is now a list of all published pages from all users

This commit is contained in:
James Taylor
2009-10-28 15:09:10 -04:00
parent d91c3fbfeb
commit d1c62cc67e
6 changed files with 194 additions and 23 deletions
+2
View File
@@ -545,6 +545,8 @@ Page.table = Table( "page", metadata,
ForeignKey( "page_revision.id", use_alter=True, name='page_latest_revision_id_fk' ), index=True ),
Column( "title", TEXT ),
Column( "slug", TEXT, unique=True, index=True ),
Column( "published", Boolean, index=True, default=False ),
Column( "deleted", Boolean, index=True, default=False ),
)
PageRevision.table = Table( "page_revision", metadata,
@@ -0,0 +1,35 @@
"""
Migration script to add columns for tracking whether pages are deleted and
publicly accessible.
"""
from sqlalchemy import *
from migrate import *
from migrate.changeset import *
import logging
log = logging.getLogger( __name__ )
metadata = MetaData( migrate_engine )
def upgrade():
print __doc__
metadata.reflect()
Page_table = Table( "page", metadata, autoload=True )
c = Column( "published", Boolean, index=True, default=False )
c.create( Page_table )
assert c is Page_table.c.published
c = Column( "deleted", Boolean, index=True, default=False )
c.create( Page_table )
assert c is Page_table.c.deleted
def downgrade():
metadata.reflect()
Page_table = Table( "page", metadata, autoload=True )
Page_table.c.published.drop()
Page_table.c.deleted.drop()
@@ -0,0 +1,34 @@
"""
Remove unique constraint from page slugs to allow creating a page with
the same slug as a deleted page.
"""
from sqlalchemy import *
from migrate import *
from migrate.changeset import *
import datetime
now = datetime.datetime.utcnow
import logging
log = logging.getLogger( __name__ )
metadata = MetaData( migrate_engine )
def upgrade():
print __doc__
metadata.reflect()
Page_table = Table( "page", metadata, autoload=True )
i = Index( "ix_page_slug", Page_table.c.slug )
i.drop()
i = Index( "ix_page_slug", Page_table.c.slug, unique=False )
i.create()
def downgrade():
metadata.reflect()
#Page_table = Table( "page", metadata, autoload=True )
#Page_table.c.slug.alter( unique=True )
+119 -22
View File
@@ -6,16 +6,27 @@ import re
VALID_SLUG_RE = re.compile( "^[a-z0-9\-]+$" )
def format_bool( b ):
if b:
return "yes"
else:
return ""
class PublicURLColumn( grids.GridColumn ):
def get_value( self, trans, grid, item ):
username = trans.user.username or "???"
return username + "/" + item.slug
def get_link( self, trans, grid, item ):
if trans.user.username:
return dict( action='display_by_username_and_slug', username=item.user.username, slug=item.slug )
else:
return None
class OwnerColumn( grids.GridColumn ):
def get_value( self, trans, grid, item ):
return item.user.username
class PageListGrid( grids.Grid ):
class URLColumn( grids.GridColumn ):
def get_value( self, trans, grid, item ):
username = trans.user.username or "???"
return username + "/" + item.slug
def get_link( self, trans, grid, item ):
if trans.user.username:
return dict( action='display_by_username_and_slug', username=item.user.username, slug=item.slug )
else:
return None
# Grid definition
use_panels = True
title = "Your pages"
@@ -23,7 +34,8 @@ class PageListGrid( grids.Grid ):
default_sort_key = "-create_time"
columns = [
grids.GridColumn( "Title", key="title", attach_popup=True ),
URLColumn( "Public URL" ),
PublicURLColumn( "Public URL" ),
grids.GridColumn( "Published", key="published", format=format_bool ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
]
@@ -32,25 +44,67 @@ class PageListGrid( grids.Grid ):
]
operations = [
grids.GridOperation( "View", allow_multiple=False, url_args=dict( action='display') ),
grids.GridOperation( "Edit", allow_multiple=False, url_args=dict( action='edit') )
grids.GridOperation( "Edit name/id", allow_multiple=False, url_args=dict( action='edit') ),
grids.GridOperation( "Edit content", allow_multiple=False, url_args=dict( action='edit_content') ),
grids.GridOperation( "Delete" ),
grids.GridOperation( "Publish", condition=( lambda item: not item.published ) ),
grids.GridOperation( "Unpublish", condition=( lambda item: item.published ) ),
]
def apply_default_filter( self, trans, query, **kwargs ):
return query.filter_by( user=trans.user )
return query.filter_by( user=trans.user, deleted=False )
class PageAllPublishedGrid( grids.Grid ):
# Grid definition
use_panels = True
title = "Published pages from all users"
model_class = model.Page
default_sort_key = "-create_time"
columns = [
grids.GridColumn( "Title", key="title" ),
PublicURLColumn( "Public URL" ),
OwnerColumn( "Published by" ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
]
def apply_default_filter( self, trans, query, **kwargs ):
return query.filter_by( deleted=False, published=True )
class PageController( BaseController ):
list = PageListGrid()
_page_list = PageListGrid()
_all_published_list = PageAllPublishedGrid()
@web.expose
@web.require_admin
@web.require_login()
def index( self, trans, *args, **kwargs ):
# Handle operation
if 'operation' in kwargs and 'id' in kwargs:
session = trans.sa_session
operation = kwargs['operation']
ids = util.listify( kwargs['id'] )
for id in ids:
item = session.query( model.Page ).get( trans.security.decode_id( id ) )
if operation == "Delete":
item.deleted = True
elif operation == "Publish":
item.published = True
elif operation == "Unpublish":
item.published = False
session.flush()
# Build grid
grid = self.list( trans, *args, **kwargs )
grid = self._page_list( trans, *args, **kwargs )
# Render grid wrapped in panels
return trans.fill_template( "page/index.mako", grid=grid )
@web.expose
@web.require_admin
@web.require_login()
def list_published( self, trans, *args, **kwargs ):
grid = self._all_published_list( trans, *args, **kwargs )
# Render grid wrapped in panels
return trans.fill_template( "page/index.mako", grid=grid )
@web.expose
@web.require_login( "create pages" )
def create( self, trans, page_title="", page_slug="" ):
"""
@@ -65,7 +119,7 @@ class PageController( BaseController ):
page_slug_err = "Page id is required"
elif not VALID_SLUG_RE.match( page_slug ):
page_slug_err = "Page identifier must consist of only lowercase letters, numbers, and the '-' character"
elif trans.sa_session.query( model.Page ).filter_by( user=user, slug=page_slug ).first():
elif trans.sa_session.query( model.Page ).filter_by( user=user, slug=page_slug, deleted=False ).first():
page_slug_err = "Page id must be unique"
else:
# Create the new stored workflow
@@ -98,9 +152,50 @@ class PageController( BaseController ):
template="page/create.mako" )
@web.expose
@web.require_admin
@web.require_login( "create pages" )
def edit( self, trans, id, page_title="", page_slug="" ):
"""
Create a new page
"""
encoded_id = id
id = trans.security.decode_id( id )
session = trans.sa_session
page = session.query( model.Page ).get( id )
user = trans.user
assert page.user == user
page_title_err = page_slug_err = ""
if trans.request.method == "POST":
if not page_title:
page_title_err = "Page name is required"
elif not page_slug:
page_slug_err = "Page id is required"
elif not VALID_SLUG_RE.match( page_slug ):
page_slug_err = "Page identifier must consist of only lowercase letters, numbers, and the '-' character"
elif page_slug == page.slug or trans.sa_session.query( model.Page ).filter_by( user=user, slug=page_slug, deleted=False ).first():
page_slug_err = "Page id must be unique"
else:
page.title = page_title
page.slug = page_slug
session.flush()
# Display the management page
return trans.response.send_redirect( web.url_for( action='index' ) )
else:
page_title = page.title
page_slug = page.slug
return trans.show_form(
web.FormBuilder( web.url_for( id=encoded_id ), "Edit page attributes", submit_text="Submit" )
.add_text( "page_title", "Page title", value=page_title, error=page_title_err )
.add_text( "page_slug", "Page identifier", value=page_slug, error=page_slug_err,
help="""A unique identifier that will be used for
public links to this page. A default is generated
from the page title, but can be edited. This field
must contain only lowercase letters, numbers, and
the '-' character.""" ),
template="page/create.mako" )
@web.expose
@web.require_login( "edit pages" )
def edit( self, trans, id ):
def edit_content( self, trans, id ):
"""
Render the main page editor interface.
"""
@@ -110,7 +205,7 @@ class PageController( BaseController ):
return trans.fill_template( "page/editor.mako", page=page )
@web.expose
@web.require_admin
@web.require_login()
def save( self, trans, id, content ):
id = trans.security.decode_id( id )
page = trans.sa_session.query( model.Page ).get( id )
@@ -126,10 +221,12 @@ class PageController( BaseController ):
trans.sa_session.flush()
@web.expose
@web.require_admin
@web.require_login()
def display( self, trans, id ):
id = trans.security.decode_id( id )
page = trans.sa_session.query( model.Page ).get( id )
if page.user is not trans.user:
error( "Page is not owned by current user" )
return trans.fill_template( "page/display.mako", page=page )
@web.expose
@@ -138,7 +235,7 @@ class PageController( BaseController ):
user = session.query( model.User ).filter_by( username=username ).first()
if user is None:
raise web.httpexceptions.HTTPNotFound()
page = trans.sa_session.query( model.Page ).filter_by( user=user, slug=slug ).first()
page = trans.sa_session.query( model.Page ).filter_by( user=user, slug=slug, deleted=False, published=True ).first()
if page is None:
raise web.httpexceptions.HTTPNotFound()
return trans.fill_template( "page/display.mako", page=page )
+1 -1
View File
@@ -279,7 +279,7 @@ class GridOperation( object ):
temp['id'] = item.id
return temp
else:
return dict( operation=operation.label, id=item.id )
return dict( operation=self.label, id=item.id )
def allowed( self, item ):
if self.condition:
+3
View File
@@ -243,6 +243,9 @@
<li><hr style="color: inherit; background-color: gray"/></li>
<li><a target="galaxy_main" href="${h.url_for( controller='history', action='list' )}">Histories</a></li>
<li><a target="galaxy_main" href="${h.url_for( controller='dataset', action='list' )}">Datasets</a></li>
%if app.config.get_bool( 'enable_pages', False ):
<li><a href="${h.url_for( controller='page' )}">Pages</a></li>
%endif
%endif
</ul>
</div>