Source

c5t / c5t / core / controllers / page.py

Full commit
# -*- coding: utf-8 -*-
"""Page Controller"""

import shutil
from files import PageFilesController
from tg import expose, require, request, redirect, tmpl_context, response, flash, validate
from tg.render import render_mako ,_get_tg_vars
from pylons.controllers.util import abort
from pylons import config

from tg.util import DottedFileNameFinder
from tg.decorators import with_trailing_slash

template_finder = DottedFileNameFinder()

from tg.controllers import RestController
from c5t.core.model.content import Page, File
from c5t.core.model.session import main_orm_session
from c5t.core.lib.decorators import registered_validate, register_validators
from c5t.core.lib.keywordprocessor import KeywordProcessor

from pymongo.objectid import ObjectId

from repoze.what.predicates import Any
from c5t.core.lib.authn import HasAnyRole, IsPublic
from c5t.core.forms.page import NewPageForm, EditPageForm
from c5t.core.lib.helpers import strip_tags
try:
  from c5t.news.model import News
except:
  pass
# from news import NewsController

def render(template, template_vars):
    template_vars['tmpl_context'] = tmpl_context
    template_vars.update(_get_tg_vars())
    return render_mako(template, template_vars)


new_page_form = NewPageForm(action='./')
edit_page_form = EditPageForm(action='./')

tag_parser = KeywordProcessor(' \t,', normalize=lambda s: s.lower().strip('"'), sort=True, result=list)


class PageController(RestController):

    # Load the templates from the config file
    default_custom_template_path    = config.get('c5t.template.page.custom', 'c5t.core.templates.page.custom')
    default_template_name           = config.get('c5t.template.page.default', 'c5t.core.templates.page.default')
    boilerplate_template_path       = config.get('c5t.template.page.default', 'c5t.core.templates.page.default')

    # right now Ming doesn't handle
    # inheritance for searches very well, so
    # page controllers are restricted to the
    # subclass of page
    page_type = Page

    # allows you to override the forms for your
    # type of page.
    new_form = new_page_form
    edit_form = edit_page_form

    def __init__(self, slug=None, page=None):

        self.slug = slug
        self.page = page
        tmpl_context.parent_id = None
        if self.page:
            tmpl_context.parent_id = page._id
        # self.default_home_path = config['files.path']
        self.files = PageFilesController() # page_slug=slug, home_path=self.default_home_path

        if hasattr(self, 'new_form'):
            #register the validators since they are none from the parent class
            register_validators(self, 'post', self.new_form)
        if hasattr(self, 'edit_form'):
            register_validators(self, 'put', self.edit_form)

    @require(Any(IsPublic(), HasAnyRole('admin', 'writer', 'editor', 'user')))
    @with_trailing_slash
    @expose()
    def get_all(self):
        # required_roles = ['admin', 'writer', 'editor']
        user = tmpl_context.user

        thepage=self.page._id
               #user = tmpl_context.user
        pages = []
        #if user:
        pages = [page for page in Page.query.find({'parent_id': ObjectId(thepage)})]
        #pages = [page for page in Page.query.find()._addSpecial( "$orderby", {'parent_id' : -1} )]
        morepages = [page for page in Page.query.find()]
        morepages = sorted(morepages, key=lambda page: page.parent_id)
        allpages = []
        for mypage in morepages:
            if mypage.parent_id == None:
                #page_id = mypage._id
                allpages.append(mypage)
                #otherpages = get_subpages(morepages[],mypage._id)
                #allpages = allpages.concat(otherpages)
                #for apage in otherpages:
                #       allpages.append(apage)
                for subpage in morepages:
                    if subpage.parent_id == mypage._id:
                        allpages.append(subpage)
                        for subpage2 in morepages:
                            if subpage2.parent_id == subpage._id:
                                allpages.append(subpage2)


        # if user and user.role in required_roles + self.page.acl:
        d = dict(page=self.page, action='Add', pages=pages, allpages=allpages)
        return render(self.page.template, d)
        # else:
        #     if response.status_int == 401:
        #         status, reason = 'warning', u'You must be logged in to view this resource.'
        #     else:
        #         # Status is a 403
        #         response.status_int = 403
        #         status, reason = 'error', u'Your account is not authorized to view this resource.'
        #     flash(reason, status='error')
        #     abort(response.status_int, reason)



    @require(HasAnyRole('admin', 'writer'))
    @expose('c5t.core.templates.page.new')
    def new(self, *args, **kw):
        new_slug = self.slug
        value = kw.copy()
        if self.slug and not 'slug' in kw:
            value['slug'] = self.slug
        if 'title' not in kw and 'slug' in value:
            value['title'] = value['slug']
        parent_id = getattr(tmpl_context, 'parent_id', None)
        if parent_id:
            value['parent_id'] = parent_id

        exc = getattr(tmpl_context, 'validation_exception', None)
        if exc:
            tmpl_context.form = exc.widget
        else:
            tmpl_context.form = self.new_form

        return dict(value=value)

    @require(HasAnyRole('admin', 'writer'))
    @registered_validate(error_handler=new)
    @expose()
    def post(self, **kw):
        #xxx: validation

        slug = kw.get('slug', self.slug)
        kw['tags'] = tag_parser.split(kw.get('tags', ''))
        # if the user has selected "boilerplate" then copy a blank template
        # into the custom templates location for future editing
        new_template_name = kw.get('template', self.default_template_name)
        if new_template_name == 'other_template_value':
            new_template_name = request.params.get('other_template_value', self.default_template_name)
        elif new_template_name == 'custom':
            new_template_name  = '.'.join((self.default_custom_template_path, slug))
            boilerplate_template_filename = template_finder.get_dotted_filename(self.boilerplate_template_path, '.mak')
            new_template_filename = template_finder.get_dotted_filename(new_template_name, '.mak')
            shutil.copy(boilerplate_template_filename, new_template_filename)

        kw['template'] = new_template_name

        url_path = ''
        parent_page_id = request.params.get('page_parent')
        if parent_page_id == 'current' or parent_page_id == None:
          raw_parent_id = kw.get('parent_id', None)
          parent_id = raw_parent_id and ObjectId(raw_parent_id) or None
          kw['parent_id'] = parent_id                  
        elif parent_page_id == 'top' or parent_page_id is None:
          kw['parent_id'] = None
        else:
          kw['parent_id'] = parent_page_id         
          parent_page = self.page_type.query.get(_id=ObjectId(parent_page_id))
          url_path = parent_page.path()+'/'+slug

        kw['slug'] = slug

        page = self.page_type()
        for key, value in kw.iteritems():
            setattr(page, key, value)

        flash('The page, "%s," has been created' % page.title)
    
        if url_path == '':
          redirect('/%s' % page.path())
        else:
          redirect('/'+url_path+'/')

    @require(HasAnyRole('admin', 'writer', 'editor'))
    @expose('c5t.core.templates.page.edit')
    def edit(self):
        exc = getattr(tmpl_context, 'validation_exception', None)
        if exc:
            tmpl_context.form = exc.widget
        else:
            tmpl_context.form = self.edit_form

        try:
            page = tmpl_context.current_page
            parent_id = tmpl_context.current_page._id
        except AttributeError:
            parent_id = tmpl_context.parent_id
            page = self.page_type.query.get(_id=parent_id)
        page['page_id'] = parent_id
        return dict(page=page)


    @registered_validate(error_handler=edit)
    @require(HasAnyRole('admin', 'writer', 'editor'))
    @expose()
    def put(self, **kw):
        #xxx: add versioning
        user = tmpl_context.user

        kw['tags'] = tag_parser.split(kw.get('tags', ''))
        
        page_id = kw.get('page_id')
        page = self.page_type.query.get(_id=ObjectId(page_id))
        del kw['page_id']
        #override the template with the "other template" selection
        new_template_name = kw.get('template', self.default_template_name)
        if new_template_name == 'other_template_value':
            new_template_name = request.params.get('other_template_value', self.default_template_name)
        elif new_template_name == 'custom':
            new_template_name  = '.'.join((self.default_custom_template_path, slug))
            boilerplate_template_filename = template_finder.get_dotted_filename(self.boilerplate_template_path, '.mak')
            new_template_filename = template_finder.get_dotted_filename(new_template_name, '.mak')
            shutil.copy(boilerplate_template_filename, new_template_filename)

        kw['template'] = new_template_name
        for k,v in kw.iteritems():
            setattr(page, k, v)

        redirect('/%s' % page.path())


    @require(HasAnyRole('admin', 'writer'))
    @expose()
    def post_delete(self, **kw):
        user = tmpl_context.user

        page_id = kw.get('page_id')
        page = Page.query.get(_id=ObjectId(page_id))
        if page is not None:
            page.delete_children()
            page.delete()


        redirect('/pages/')
        # else:
        #     if response.status_int == 401:
        #         status, reason = 'warning', u'You must be logged in to delete this resource.'
        #     else:
        #         # Status is a 403
        #         response.status_int = 403
        #         status, reason = 'error', u'Your account is not authorized to delete this resource.'
        #     flash(reason, status='error')
        #     abort(response.status_int, reason)

    @require(HasAnyRole('admin', 'writer'))
    @expose()
    def edit_post_delete(self, **kw):
        user = tmpl_context.user

        page_id = kw.get('page_id')
        page_type = kw.get('page_type')
        if page_type == 'News':
          page = News.query.get(_id=ObjectId(page_id))
        else:
          page = Page.query.get(_id=ObjectId(page_id))
        url_path = ''
        if page is not None:
            url_path = (page.path()).rstrip(page.slug)
            page.delete_children()
            page.delete()

        redirect('/'+url_path)

    @require(HasAnyRole('admin', 'writer'))
    @expose()
    def publish(self, **kw):
        user = tmpl_context.user

        page_id = request.params.get('page_id')
        page = self.page_type.query.get(_id=ObjectId(page_id))
        page.status = request.params.get('status')



        redirect('/'+page.path()+'/')
        # else:
        #     if response.status_int == 401:
        #         status, reason = 'warning', u'You must be logged in to publish this resource.'
        #     else:
        #         # Status is a 403
        #         response.status_int = 403
        #         status, reason = 'error', u'Your account is not authorized to view this resource.'
        #     flash(reason, status='error')
        #     abort(response.status_int, reason)
    @expose()
    def pageparent(self, **kw):
    	from c5t.core.model.content import Page
        required_roles = ['admin', 'writer']
        user = tmpl_context.user

        page_id = request.params.get('page_id')
        page = self.page_type.query.get(_id=ObjectId(page_id))
        parent_page_id = request.params.get('page_parent')
        if parent_page_id == 'top':
          Page.query.update({"_id": page._id}, {"$unset": {"parent_id": 1}})
          url_path = page.slug
        else:
          page.parent_id = parent_page_id
          parent_page = self.page_type.query.get(_id=ObjectId(parent_page_id))
          url_path = parent_page.path()+'/'+page.slug

        main_orm_session.flush_all()
        main_orm_session.close_all()
   
        redirect('/'+url_path+'/edit')
        
    @require(HasAnyRole('admin', 'writer', 'editor'))  
    @expose()
    def update_file(self, file_id=None, file_tags=None, ftitle=None, fdesc=None, furl=None, fpub=None):
        fdesc = strip_tags(fdesc)
        ftitle = strip_tags(ftitle)
        furl = strip_tags(furl)
        if fpub == 'true':
            fpub = True
        else:
            fpub = False
        
        if file_tags == '':
            File.query.update({"_id": ObjectId(file_id)}, {"$set": {"tags": [],'text':ftitle,'description':fdesc,'fileurl':furl,'public':fpub}})
        else:
            the_tags = file_tags.split(',')
            File.query.update({"_id": ObjectId(file_id)}, {"$set": {"tags": the_tags,'text':ftitle,'description':fdesc,'fileurl':furl,'public':fpub}})
                
    @require(HasAnyRole('admin', 'writer', 'editor'))
    @expose()      
    def validate_slug(self, page_slug, parent_page_id, page_id):
        if parent_page_id == 'top' or parent_page_id == '':
          page = Page.query.get(slug=page_slug,parent_id=None)
        else:
          page = Page.query.get(slug=page_slug,parent_id=ObjectId(parent_page_id))
        if page:
          if page_id == 'None':
    	      return 'Error: Duplicate slug'
          else:
            if page._id != ObjectId(page_id):
    	      return 'Error: Duplicate slug'
    	              
class PagesController(PageController):
    files = None

    @with_trailing_slash
    @require(HasAnyRole('admin', 'writer', 'editor', 'user'))
    @expose('c5t.core.templates.pages.index')
    def get_all(self, sort_by=None):
        # pages = Page.query.find()
        # return dict(page='pages', pages=pages)
        if sort_by is None:
            sort_by = 'slug'

        required_roles = ['admin', 'editor', 'writer']
        user = tmpl_context.user

        pages = []
        if user:
            pages = [page for page in Page.query.find().sort(sort_by) if user.role in required_roles + page.acl]
        return dict(page='pages', pages=pages)