<commit_before>from urllib import unquote
from mimetypes import guess_type
import Image
import os

from tg import expose, flash, redirect, validate, request, response
from tg.decorators import with_trailing_slash, without_trailing_slash
from pylons import c, g
from webob import exc
from pymongo.bson import ObjectId
from formencode import validators

import  ming.orm.ormsession

import pyforge
from pyforge import model as M
from pyforge.app import SitemapEntry
from pyforge.lib.base import BaseController
from pyforge.lib import helpers as h
from pyforge.controllers.error import ErrorController
from pyforge.lib.security import require, has_project_access, has_neighborhood_access
from pyforge.lib.widgets import form_fields as ffw
from pyforge.lib.widgets import project_list as plw
from .auth import AuthController
from .search import SearchController, ProjectBrowseController
from .static import StaticController

from mako.template import Template
from pyforge.model.session import main_orm_session

CACHED_CSS = dict()

class W:
    markdown_editor = ffw.MarkdownEdit()
    project_summary = plw.ProjectSummary()

class NeighborhoodController(object):
    '''Manages a neighborhood of projects.
    '''

    def __init__(self, neighborhood_name, prefix=''):
        self.neighborhood_name = neighborhood_name
        self.neighborhood = M.Neighborhood.query.get(name=self.neighborhood_name)
        self.prefix = prefix
        self.browse = NeighborhoodProjectBrowseController(neighborhood=self.neighborhood)
        self._admin = NeighborhoodAdminController(self.neighborhood)
        self._moderate = NeighborhoodModerateController(self.neighborhood)
    
    def _check_security(self):
        require(has_neighborhood_access('read', self.neighborhood),
                'Read access required')

    @expose()
    def _lookup(self, pname, *remainder):
        if not h.re_path_portion.match(pname):
            raise exc.HTTPNotFound, pname
        project = M.Project.query.get(shortname=self.prefix + pname)
        if project is None:
            raise exc.HTTPNotFound, pname
        if project.neighborhood.name != self.neighborhood_name:
            redirect(project.url())
        c.project = project
        return ProjectController(), remainder

    @expose('pyforge.templates.neighborhood_project_list')
    def index(self):
        c.project_summary = W.project_summary
        projects = M.Project.query.find(dict(neighborhood_id=self.neighborhood._id)).sort('name').all()
        categories = M.ProjectCategory.query.find({'parent_id':None}).sort('name').all()
        c.custom_sidebar_menu = [SitemapEntry('Categories')] + [
            SitemapEntry(cat.label, self.neighborhood.url()+'browse/'+cat.name, className='nav_child') for cat in categories
        ]
        return dict(neighborhood=self.neighborhood,
                    title="Welcome to "+self.neighborhood.name,
                    text=g.markdown.convert(self.neighborhood.homepage),
                    projects=projects)

    @expose()
    def register(self, pid):
        if not h.re_path_portion.match(pid):
            flash('Invalid project shortname "%s"' % pid, 'error')
            redirect(request.referer)
        require(has_neighborhood_access('create', self.neighborhood), 'Create access required')
        try:
            p = self.neighborhood.register_project(pid)
        except Exception, ex:
            c.project = None
            ming.orm.ormsession.ThreadLocalORMSession.close_all()
            flash('%s: %s' % (ex.__class__, str(ex)), 'error')
            redirect('.')
        redirect(p.script_name + 'admin/')

    @expose()
    def icon(self):
        with self.neighborhood.icon.open() as fp:
            filename = fp.metadata['filename']
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type
            response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
        return self.neighborhood.icon.filename

    @expose()
    @without_trailing_slash
    def site_style(self):
        """Display the css for the default theme."""
        if self.neighborhood._id in CACHED_CSS:
            css = CACHED_CSS[self.neighborhood._id]
        else:
            theme = M.Theme.query.find(dict(neighborhood_id=self.neighborhood._id)).first()
            if theme == None:
                theme = M.Theme.query.find(dict(name='forge_default')).first()
            
            template_path = os.path.join(pyforge.__path__[0],'templates')
            file_path = os.path.join(template_path,'style.mak')
            colors = dict(color1=theme.color1,
                          color2=theme.color2,
                          color3=theme.color3,
                          color4=theme.color4)
            css = Template(filename=file_path, module_directory=template_path).render(**colors)
            if self.neighborhood.css:
                css = css + Template(self.neighborhood.css).render(**colors)
            CACHED_CSS[self.neighborhood._id] = css
        response.headers['Content-Type'] = ''
        response.content_type = 'text/css'
        return css

class NeighborhoodProjectBrowseController(ProjectBrowseController):
    def __init__(self, neighborhood=None, category_name=None, parent_category=None):
        self.neighborhood = neighborhood
        super(NeighborhoodProjectBrowseController, self).__init__(category_name=category_name, parent_category=parent_category)
        self.nav_stub = '%sbrowse/' % self.neighborhood.url()
        self.additional_filters = {'neighborhood_id':self.neighborhood._id}

    @expose()
    def _lookup(self, category_name, *remainder):
        return NeighborhoodProjectBrowseController(neighborhood=self.neighborhood, category_name=category_name, parent_category=self.category), remainder

    @expose('pyforge.templates.neighborhood_project_list')
    @without_trailing_slash
    def index(self):
        c.project_summary = W.project_summary
        projects = self._find_projects()
        title=self._build_title()
        c.custom_sidebar_menu = self._build_nav()
        return dict(projects=projects,
                    title=title,
                    text=None,
                    neighborhood=self.neighborhood)

class HostNeighborhoodController(BaseController, NeighborhoodController):
    '''Neighborhood controller with support for use as a root controller, for
    instance, when using adobe.sourceforge.net (if this is allowed).
    '''

    auth = AuthController()
    error = ErrorController()
    static = StaticController()
    search = SearchController()

class ProjectController(object):

    def __init__(self):
        setattr(self, 'feed.rss', self.feed)
        setattr(self, 'feed.atom', self.feed)
        self.screenshot = ScreenshotsController()

    @expose()
    def _lookup(self, name, *remainder):
        if not h.re_path_portion.match(name):
            raise exc.HTTPNotFound, name
        subproject = M.Project.query.get(shortname=c.project.shortname + '/' + name)
        if subproject:
            c.project = subproject
            c.app = None
            return ProjectController(), remainder
        app = c.project.app_instance(name)
        if app is None:
            raise exc.HTTPNotFound, name
        c.app = app
        return app.root, remainder

    def _check_security(self):
        require(has_project_access('read'),
                'Read access required')

    @expose()
    @with_trailing_slash
    def index(self):
        if c.project.shortname.startswith('users/'):
            redirect('profile/')
        else:
            redirect('home/')

    @expose('pyforge.templates.project_sitemap')
    @without_trailing_slash
    def sitemap(self): # pragma no cover
        raise NotImplementedError, 'sitemap'
        require(has_project_access('read'))
        return dict()

    @without_trailing_slash
    @expose()
    @validate(dict(
            since=h.DateTimeConverter(if_empty=None),
            until=h.DateTimeConverter(if_empty=None),
            offset=validators.Int(if_empty=None),
            limit=validators.Int(if_empty=None)))
    def feed(self, since=None, until=None, offset=None, limit=None):
        if request.environ['PATH_INFO'].endswith('.atom'):
            feed_type = 'atom'
        else:
            feed_type = 'rss'
        title = 'Recent changes to Project %s' % c.project.name
        feed = M.Feed.feed(
            {'artifact_reference.project_id':c.project._id},
            feed_type,
            title,
            c.project.url(),
            title,
            since, until, offset, limit)
        response.headers['Content-Type'] = ''
        response.content_type = 'application/xml'
        return feed.writeString('utf-8')

    @expose()
    def icon(self):
        with c.project.icon.open() as fp:
            filename = fp.metadata['filename']
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type
            response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
        return c.project.icon.filename

class ScreenshotsController(object):

    @expose()
    def _lookup(self, filename, *args):
        return ScreenshotController(filename), args

class ScreenshotController(object):

    def __init__(self, filename):
        self.filename = filename

    @expose()
    def index(self, embed=False):
        screenshot = M.ProjectFile.query.find({'metadata.project_id':c.project._id, 'metadata.category':'screenshot', 'filename':self.filename}).first()
        with screenshot.open() as fp:
            filename = fp.metadata['filename']
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type
            if not embed:
                response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
        return self.filename

    @expose()
    def thumb(self, embed=False):
        thumb = M.ProjectFile.query.find({'metadata.project_id':c.project._id, 'metadata.category':'screenshot_thumb', 'metadata.filename':self.filename}).first()
        with thumb.open() as fp:
            filename = fp.metadata['filename']
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type
            if not embed:
                response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()<commit_msg>Temporary fix to header encoding issue for mod_wsgi<commit_after>from urllib import unquote
from mimetypes import guess_type
import Image
import os

from tg import expose, flash, redirect, validate, request, response
from tg.decorators import with_trailing_slash, without_trailing_slash
from pylons import c, g
from webob import exc
from pymongo.bson import ObjectId
from formencode import validators

import  ming.orm.ormsession

import pyforge
from pyforge import model as M
from pyforge.app import SitemapEntry
from pyforge.lib.base import BaseController
from pyforge.lib import helpers as h
from pyforge.controllers.error import ErrorController
from pyforge.lib.security import require, has_project_access, has_neighborhood_access
from pyforge.lib.widgets import form_fields as ffw
from pyforge.lib.widgets import project_list as plw
from .auth import AuthController
from .search import SearchController, ProjectBrowseController
from .static import StaticController

from mako.template import Template
from pyforge.model.session import main_orm_session

CACHED_CSS = dict()

class W:
    markdown_editor = ffw.MarkdownEdit()
    project_summary = plw.ProjectSummary()

class NeighborhoodController(object):
    '''Manages a neighborhood of projects.
    '''

    def __init__(self, neighborhood_name, prefix=''):
        self.neighborhood_name = neighborhood_name
        self.neighborhood = M.Neighborhood.query.get(name=self.neighborhood_name)
        self.prefix = prefix
        self.browse = NeighborhoodProjectBrowseController(neighborhood=self.neighborhood)
        self._admin = NeighborhoodAdminController(self.neighborhood)
        self._moderate = NeighborhoodModerateController(self.neighborhood)
    
    def _check_security(self):
        require(has_neighborhood_access('read', self.neighborhood),
                'Read access required')

    @expose()
    def _lookup(self, pname, *remainder):
        if not h.re_path_portion.match(pname):
            raise exc.HTTPNotFound, pname
        project = M.Project.query.get(shortname=self.prefix + pname)
        if project is None:
            raise exc.HTTPNotFound, pname
        if project.neighborhood.name != self.neighborhood_name:
            redirect(project.url())
        c.project = project
        return ProjectController(), remainder

    @expose('pyforge.templates.neighborhood_project_list')
    def index(self):
        c.project_summary = W.project_summary
        projects = M.Project.query.find(dict(neighborhood_id=self.neighborhood._id)).sort('name').all()
        categories = M.ProjectCategory.query.find({'parent_id':None}).sort('name').all()
        c.custom_sidebar_menu = [SitemapEntry('Categories')] + [
            SitemapEntry(cat.label, self.neighborhood.url()+'browse/'+cat.name, className='nav_child') for cat in categories
        ]
        return dict(neighborhood=self.neighborhood,
                    title="Welcome to "+self.neighborhood.name,
                    text=g.markdown.convert(self.neighborhood.homepage),
                    projects=projects)

    @expose()
    def register(self, pid):
        if not h.re_path_portion.match(pid):
            flash('Invalid project shortname "%s"' % pid, 'error')
            redirect(request.referer)
        require(has_neighborhood_access('create', self.neighborhood), 'Create access required')
        try:
            p = self.neighborhood.register_project(pid)
        except Exception, ex:
            c.project = None
            ming.orm.ormsession.ThreadLocalORMSession.close_all()
            flash('%s: %s' % (ex.__class__, str(ex)), 'error')
            redirect('.')
        redirect(p.script_name + 'admin/')

    @expose()
    def icon(self):
        with self.neighborhood.icon.open() as fp:
            filename = fp.metadata['filename'].encode('utf-8')
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type.encode('utf-8')
            response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
        return self.neighborhood.icon.filename

    @expose()
    @without_trailing_slash
    def site_style(self):
        """Display the css for the default theme."""
        if self.neighborhood._id in CACHED_CSS:
            css = CACHED_CSS[self.neighborhood._id]
        else:
            theme = M.Theme.query.find(dict(neighborhood_id=self.neighborhood._id)).first()
            if theme == None:
                theme = M.Theme.query.find(dict(name='forge_default')).first()
            
            template_path = os.path.join(pyforge.__path__[0],'templates')
            file_path = os.path.join(template_path,'style.mak')
            colors = dict(color1=theme.color1,
                          color2=theme.color2,
                          color3=theme.color3,
                          color4=theme.color4)
            css = Template(filename=file_path, module_directory=template_path).render(**colors)
            if self.neighborhood.css:
                css = css + Template(self.neighborhood.css).render(**colors)
            CACHED_CSS[self.neighborhood._id] = css
        response.headers['Content-Type'] = ''
        response.content_type = 'text/css'
        return css

class NeighborhoodProjectBrowseController(ProjectBrowseController):
    def __init__(self, neighborhood=None, category_name=None, parent_category=None):
        self.neighborhood = neighborhood
        super(NeighborhoodProjectBrowseController, self).__init__(category_name=category_name, parent_category=parent_category)
        self.nav_stub = '%sbrowse/' % self.neighborhood.url()
        self.additional_filters = {'neighborhood_id':self.neighborhood._id}

    @expose()
    def _lookup(self, category_name, *remainder):
        return NeighborhoodProjectBrowseController(neighborhood=self.neighborhood, category_name=category_name, parent_category=self.category), remainder

    @expose('pyforge.templates.neighborhood_project_list')
    @without_trailing_slash
    def index(self):
        c.project_summary = W.project_summary
        projects = self._find_projects()
        title=self._build_title()
        c.custom_sidebar_menu = self._build_nav()
        return dict(projects=projects,
                    title=title,
                    text=None,
                    neighborhood=self.neighborhood)

class HostNeighborhoodController(BaseController, NeighborhoodController):
    '''Neighborhood controller with support for use as a root controller, for
    instance, when using adobe.sourceforge.net (if this is allowed).
    '''

    auth = AuthController()
    error = ErrorController()
    static = StaticController()
    search = SearchController()

class ProjectController(object):

    def __init__(self):
        setattr(self, 'feed.rss', self.feed)
        setattr(self, 'feed.atom', self.feed)
        self.screenshot = ScreenshotsController()

    @expose()
    def _lookup(self, name, *remainder):
        if not h.re_path_portion.match(name):
            raise exc.HTTPNotFound, name
        subproject = M.Project.query.get(shortname=c.project.shortname + '/' + name)
        if subproject:
            c.project = subproject
            c.app = None
            return ProjectController(), remainder
        app = c.project.app_instance(name)
        if app is None:
            raise exc.HTTPNotFound, name
        c.app = app
        return app.root, remainder

    def _check_security(self):
        require(has_project_access('read'),
                'Read access required')

    @expose()
    @with_trailing_slash
    def index(self):
        if c.project.shortname.startswith('users/'):
            redirect('profile/')
        else:
            redirect('home/')

    @expose('pyforge.templates.project_sitemap')
    @without_trailing_slash
    def sitemap(self): # pragma no cover
        raise NotImplementedError, 'sitemap'
        require(has_project_access('read'))
        return dict()

    @without_trailing_slash
    @expose()
    @validate(dict(
            since=h.DateTimeConverter(if_empty=None),
            until=h.DateTimeConverter(if_empty=None),
            offset=validators.Int(if_empty=None),
            limit=validators.Int(if_empty=None)))
    def feed(self, since=None, until=None, offset=None, limit=None):
        if request.environ['PATH_INFO'].endswith('.atom'):
            feed_type = 'atom'
        else:
            feed_type = 'rss'
        title = 'Recent changes to Project %s' % c.project.name
        feed = M.Feed.feed(
            {'artifact_reference.project_id':c.project._id},
            feed_type,
            title,
            c.project.url(),
            title,
            since, until, offset, limit)
        response.headers['Content-Type'] = ''
        response.content_type = 'application/xml'
        return feed.writeString('utf-8')

    @expose()
    def icon(self):
        with c.project.icon.open() as fp:
            filename = fp.metadata['filename'].encode('utf-8')
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type.encode('utf-8')
            response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
        return c.project.icon.filename

class ScreenshotsController(object):

    @expose()
    def _lookup(self, filename, *args):
        return ScreenshotController(filename), args

class ScreenshotController(object):

    def __init__(self, filename):
        self.filename = filename

    @expose()
    def index(self, embed=False):
        screenshot = M.ProjectFile.query.find({'metadata.project_id':c.project._id, 'metadata.category':'screenshot', 'filename':self.filename}).first()
        with screenshot.open() as fp:
            filename = fp.metadata['filename'].encode('utf-8')
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type.encode('utf-8')
            if not embed:
                response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
        return self.filename

    @expose()
    def thumb(self, embed=False):
        thumb = M.ProjectFile.query.find({'metadata.project_id':c.project._id, 'metadata.category':'screenshot_thumb', 'metadata.filename':self.filename}).first()
        with thumb.open() as fp:
            filename = fp.metadata['filename'].encode('utf-8')
            response.headers['Content-Type'] = ''
            response.content_type = fp.content_type.encode('utf-8')
            if not embed:
                response.headers.add('Content-Disposition',
                                     'attachment;filename=%s' % filename)
            return fp.read()
{'fraction_non_alphanumeric': 0.10658394295768127, 'fraction_numerical': 0.0012964163348458191, 'mean_word_length': 2.6300840336134454, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3090543', 'n_tokens_mistral': 6117, 'n_tokens_neox': 5863, 'n_words': 1182}