Source

c5t / c5t / core / controllers / files.py

Full commit
import os, urllib
import Image
from pkg_resources import resource_filename

from pylons import config
from pylons.controllers.util import abort

from paste.fileapp import FileApp
from repoze.what.predicates import Any

from tg import expose, flash, require, request, redirect, tmpl_context
from tg.util import DottedFileNameFinder
from tg.controllers import RestController


from c5t.core.lib.helpers import strip_tags
from c5t.core.model.content import File
from c5t.core.lib.authn import HasAnyRole, IsPublic
from c5t.core.model.session import main_orm_session
from c5t.core.util import get_real_package_root
from c5t.core.lib.keywordprocessor import KeywordProcessor

template_finder = DottedFileNameFinder()

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

class PageFilesController(RestController):
    def _before(self, *args, **kw):
        if hasattr(request, 'state'):
            #TG 2.1b2+ support
            current_page = request.state.current_page
        else:
            #TG 2.1b1 support (deprecated)
            #import warnings
            #warnings.warn('modifying tmpl_context within dispatch is deprecated.  Please install TG2.1b2 or higher')
            current_page = tmpl_context.current_page

        tmpl_context.page = current_page

    def _file_from_url(self):
        '''Only call this after calling _before()'''
        title = urllib.unquote(request.url.split('/')[-1])
        file_ = File.query.get(title=title, parent_id=tmpl_context.page._id)

        if not file_:
            abort(404)

        return file_

    # def __init__(self, page_slug=None, module=None):
        # self.page_slug = page_slug
        # if module is None:
        #     module = config['pylons.package']
        # self.module_path = template_finder.get_dotted_filename(module, template_extension='')

        # self.home = os.path.join(template_path, home_path)
        # pass

    # this should only be used on private files
    @require(Any(IsPublic(), HasAnyRole('admin', 'writer', 'editor', 'user')))
    @expose()
    def get_one(self, *args):
        file_path = self._file_from_url().filepath()
        try:
            fileapp = FileApp(file_path)
            return fileapp(request.environ, request.start_response)
        except (OSError, IOError):
            abort(404, 'That file has gone missing')

    @require(HasAnyRole('admin', 'writer', 'editor'))
    @expose()
    def post_delete(self, *args):
        user = tmpl_context.user
        file_ = self._file_from_url()
#        if user and user.role in file_.acl:
            # delete the file from the actual filesystem
        if not file_.fileurl:
            file_path = file_.filepath()
            try:
                os.remove(file_path)
            except OSError, e:
                if e.errno not in (os.errno.ENOENT,):
                    raise
        # delete the object from the db
        file_.delete()

        main_orm_session.flush_all()
        main_orm_session.close_all()
        redirect('../')

    @require(HasAnyRole('admin', 'writer', 'editor'))
    @expose()
    def post(self, data=None, public=None, label=None, description=None, fileurl=None, filetags=None):
        description = strip_tags(description)
        label = strip_tags(label)
        fileurl = strip_tags(fileurl)
        if fileurl == '':
          fileurl = None
        if fileurl is None:
            if not hasattr(data, 'filename'):
                flash('You must select a file to add.', 'error')
                redirect('./')
            user = tmpl_context.user
	    
            filename = data.filename
            file_type = data.type
            data = data.value
	    
            public = public == 'on'
	    
            text = label
            file_tags = tag_parser.split(filetags)
            file_ = File(parent_id=tmpl_context.page._id, title=filename, public=public, description=description, fileurl=fileurl, text=text,
                format=file_type, tags=file_tags, acl=[user.role])
	    
            package_root = get_real_package_root(config['pylons.package'])
	    
            file_dir = os.path.join(package_root, 'public', 'pages', file_.parent.path())
            file_path = os.path.join(file_dir, file_.title)
	    
            if not os.path.exists(file_dir):
                try:
                    os.makedirs(file_dir)
                except OSError:
                    f.delete()
	    
            #xxx if the File already exists, don't overwrite add a -1 or something
            try:
                f = file(file_path, 'w')
                f.write(data)
                f.flush()
                f.close()
            except (IOError, OSError):
                f.delete()
	    
            if file_type[:6] == 'image/':
	    
                # generate a preview
                image = Image.open(file_path)
                preview_path = os.path.join(file_dir, 'p_'+filename)
                if image.size[0] > 500 or image.size[1] > 500:
                    image.thumbnail((500, 500), Image.ANTIALIAS)
                image.save(preview_path)
	    
                # generate a thumbnail
                image = Image.open(file_path)
                thumb_path = os.path.join(file_dir, 't_'+filename)
                if image.size[0] < image.size[1]:
                    h_offset = (image.size[1]-image.size[0])/2
                    image = image.crop((0, h_offset, image.size[0], image.size[0]+h_offset))
                elif image.size[0] > image.size[1]:
                    w_offset = (image.size[0]-image.size[1])/2
                    image = image.crop((w_offset, 0, image.size[1]+w_offset, image.size[1]))
                image.thumbnail((75, 75), Image.ANTIALIAS)
                image.save(thumb_path)
	    
            main_orm_session.flush_all()
            main_orm_session.close_all()
	    
            redirect('./edit')
        else:
            date = None
            user = tmpl_context.user
	    
	    #Make sure that the url is either a fully quallified url, or an absolute URL
	#    if not fileurl.startswith('/') and not fileurl.startswith('http://'):
		#This doesn't actually work, the flash message never shows up, and the edit page is removed
     #           flash('A url must either begin with a / (for files on this server) or http:// (for files not on this server).', 'error')
      #          redirect('./')
	    	
            filename = os.path.basename(fileurl)
            text = label
            file_type = 'filetype' #data.type
            data = 'filedata'
	    
            public = public == 'on'
	    
            file_tags = tag_parser.split(filetags)
            file_ = File(parent_id=tmpl_context.page._id, title=filename, public=public, description=description, fileurl=fileurl,text=text,
                format=file_type, tags=file_tags, acl=[user.role])
	    	    	    
            #xxx if the File already exists, don't overwrite add a -1 or something
            	    	    
            main_orm_session.flush_all()
            main_orm_session.close_all()
	    
            redirect('./edit')