<commit_before># -*- coding: iso8859-1 -*-
#
# Copyright (C) 2003, 2004 Edgewall Software
# Copyright (C) 2003, 2004 <NAME> <<EMAIL>>
#
# Trac is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# Trac is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Author: <NAME> <<EMAIL>>

import os, os.path
import time
import re
import types
import urllib

from util import *
from Module import Module
from Wiki import wiki_to_html
import perm

dynvars_re = re.compile('\$([A-Z]+)')
dynvars_disallowed_var_chars_re = re.compile('[^A-Z0-9_]')
dynvars_disallowed_value_chars_re = re.compile('[^a-zA-Z0-9-_@.,]')

try:
    _StringTypes = [types.StringType, types.UnicodeType]
except AttributeError:
    _StringTypes = [types.StringType]

class ColumnSorter:

    def __init__(self, columnIndex, asc=1):
        self.columnIndex = columnIndex
        self.asc = asc

    def sort(self, x, y):
        const = -1
        if not self.asc:
            const = 1

        # make sure to ignore case in comparisons
        realX = x[self.columnIndex]
        if type(realX) in _StringTypes:
            realX = realX.lower()
        realY = y[self.columnIndex]
        if type(realY) in _StringTypes:
            realY = realY.lower()

        result = 0
        if realX < realY:
            result = const * 1
        elif realX > realY:
            result = const * -1

        return result


class Report (Module):
    template_name = 'report.cs'
    template_rss_name = 'report_rss.cs'
    template_csv_name = 'report_csv.cs'

    def sql_sub_vars(self, sql, args):
        m = re.search(dynvars_re, sql)
        if not m:
            return sql
        aname=m.group()[1:]
        try:
            arg = args[aname]
        except KeyError:
            raise TracError("Dynamic variable '$%s' not defined." % aname)
        self.req.hdf.setValue('report.var.'+aname , arg)
        sql = m.string[:m.start()] + arg + m.string[m.end():]
        return self.sql_sub_vars(sql, args)
    
    def get_info(self, id, args):
        cursor = self.db.cursor()

        if id == -1:
            # If no particular report was requested, display
            # a list of available reports instead
            cursor.execute("SELECT id AS report, title "
                           "FROM report "
                           "ORDER BY report")
            title = 'Available reports'
            description = 'This is a list of reports available.'
        else:
            cursor.execute('SELECT title, sql, description from report '
                           ' WHERE id=%s', id)
            row = cursor.fetchone()
            try:
                if not row:
                    raise TracError('Report %d does not exist.' % id,
                                'Invalid Report Number')
                title = row[0] or ''
                sql   = self.sql_sub_vars(row[1], args)
                if not sql:
                    raise TracError('Report %s has no SQL query.' % id)
                description = row[2] or ''
                cursor.execute(sql)

                if sql.find('__group__') == -1:
                    self.req.hdf.setValue('report.sorting.enabled', '1')

            except Exception, e:
                self.error = e
                self.req.hdf.setValue('report.message',
                                      'report failed: %s' % e)
                return None

        # FIXME: fetchall should probably not be used.
        info = cursor.fetchall()
        cols = cursor.rs.col_defs
        # Escape the values so that they are safe to have as html parameters
#        info = map(lambda row: map(lambda x: escape(x), row), info)
        return [cols, info, title, description]
        
    def create_report(self, title, description, sql):
        self.perm.assert_permission(perm.REPORT_CREATE)

        cursor = self.db.cursor()
        cursor.execute('INSERT INTO report (id, title, sql, description)'
                        'VALUES (NULL, %s, %s, %s)', title, sql, description)
        id = self.db.db.sqlite_last_insert_rowid()
        self.db.commit()
        self.req.redirect(self.env.href.report(id))

    def delete_report(self, id):
        self.perm.assert_permission(perm.REPORT_DELETE)

        if self.args.has_key('delete'):
            cursor = self.db.cursor ()
            cursor.execute('DELETE FROM report WHERE id=%s', id)
            self.db.commit()
            self.req.redirect(self.env.href.report())
        else:
            self.req.redirect(self.env.href.report(id))

    def commit_changes(self, id):
        """
        saves report changes to the database
        """
        self.perm.assert_permission(perm.REPORT_MODIFY)

        cursor = self.db.cursor()
        title = self.args.get('title', '')
        sql   = self.args.get('sql', '')
        description   = self.args.get('description', '')

        cursor.execute('UPDATE report SET title=%s, sql=%s, description=%s '
                       ' WHERE id=%s',
                       title, sql, description, id)
        self.db.commit()
        self.req.redirect(self.env.href.report(id))

    def render_confirm_delete(self, id):
        self.perm.assert_permission(perm.REPORT_DELETE)
        cursor = self.db.cursor()

        cursor.execute('SELECT title FROM report WHERE id = %s', id)
        row = cursor.fetchone()
        if not row:
            raise TracError('Report %s does not exist.' % id,
                            'Invalid Report Number')
        self.req.hdf.setValue('title', '%s (report)' % row['title'])
        self.req.hdf.setValue('report.mode', 'delete')
        self.req.hdf.setValue('report.id', str(id))
        self.req.hdf.setValue('report.title', row['title'])

    def render_report_editor(self, id, action='commit', copy=0):
        self.perm.assert_permission(perm.REPORT_MODIFY)
        cursor = self.db.cursor()

        if id == -1:
            title = sql = description = ''
        else:
            cursor.execute('SELECT title, description, sql FROM report '
                           ' WHERE id=%s', id)
            row = cursor.fetchone()
            if not row:
                raise TracError('Report %s does not exist.' % id,
                                'Invalid Report Number')
            sql = row[2] or ''
            description = row[1] or ''
            title = row[0] or ''

        if copy:
            title += ' copy'
        
        self.req.hdf.setValue('report.mode', 'editor')
        self.req.hdf.setValue('report.title', title)
        self.req.hdf.setValue('report.id', str(id))
        self.req.hdf.setValue('report.action', action)
        self.req.hdf.setValue('report.sql', sql)
        self.req.hdf.setValue('report.description', description)

    def add_alternate_links(self, args):
        params = args
        if self.args.has_key('sort'):
            params['sort'] = self.args['sort']
        if self.args.has_key('asc'):
            params['asc'] = self.args['asc']
        href = ''
        if params:
            href = '&amp;' + urllib.urlencode(params).replace('&', '&amp;')
        self.add_link('alternate', '?format=rss' + href, 'RSS Feed',
            'application/rss+xml', 'rss')
        self.add_link('alternate', '?format=csv' + href,
            'Comma-delimited Text', 'text/plain')
        self.add_link('alternate', '?format=tab' + href,
            'Tab-delimited Text', 'text/plain')
        if self.perm.has_permission(perm.REPORT_SQL_VIEW):
            self.add_link('alternate', '?format=sql' + href, 'SQL Query',
                'text/plain')

    def render_report_list(self, id):
        """
        uses a user specified sql query to extract some information
        from the database and presents it as a html table.
        """
        if self.perm.has_permission(perm.REPORT_CREATE):
            self.req.hdf.setValue('report.create_href',
                                  self.env.href.report(None, 'new'))
            
        if id != -1:
            self.add_alternate_links(args)
            if self.perm.has_permission(perm.REPORT_MODIFY):
                self.req.hdf.setValue('report.edit_href',
                                      self.env.href.report(id, 'edit'))
            if self.perm.has_permission(perm.REPORT_CREATE):
                self.req.hdf.setValue('report.copy_href',
                                      self.env.href.report(id, 'copy'))
            if self.perm.has_permission(perm.REPORT_DELETE):
                self.req.hdf.setValue('report.delete_href',
                                      self.env.href.report(id, 'delete'))

        self.req.hdf.setValue('report.mode', 'list')
        info = self.get_info(id, args)
        if not info:
            return
        [self.cols, self.rows, title, description] = info
        self.error = None
        
        self.req.hdf.setValue('title', title + ' (report)')
        self.req.hdf.setValue('report.title', title)
        self.req.hdf.setValue('report.id', str(id))
        descr_html = wiki_to_html(description, self.req.hdf, self.env)
        self.req.hdf.setValue('report.description', descr_html)

        try:
            args = self.get_var_args()
        except ValueError,e:
            self.req.hdf.setValue('report.message', 'report failed: %s' % e)
            return
        
        # Convert the header info to HDF-format
        idx = 0
        for col in self.cols:
            title=col[0].capitalize()
            prefix = 'report.headers.%d' % idx<commit_msg>Fix a bug introduced in [701]<commit_after># -*- coding: iso8859-1 -*-
#
# Copyright (C) 2003, 2004 Edgewall Software
# Copyright (C) 2003, 2004 <NAME> <<EMAIL>>
#
# Trac is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# Trac is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Author: <NAME> <<EMAIL>>

import os, os.path
import time
import re
import types
import urllib

from util import *
from Module import Module
from Wiki import wiki_to_html
import perm

dynvars_re = re.compile('\$([A-Z]+)')
dynvars_disallowed_var_chars_re = re.compile('[^A-Z0-9_]')
dynvars_disallowed_value_chars_re = re.compile('[^a-zA-Z0-9-_@.,]')

try:
    _StringTypes = [types.StringType, types.UnicodeType]
except AttributeError:
    _StringTypes = [types.StringType]

class ColumnSorter:

    def __init__(self, columnIndex, asc=1):
        self.columnIndex = columnIndex
        self.asc = asc

    def sort(self, x, y):
        const = -1
        if not self.asc:
            const = 1

        # make sure to ignore case in comparisons
        realX = x[self.columnIndex]
        if type(realX) in _StringTypes:
            realX = realX.lower()
        realY = y[self.columnIndex]
        if type(realY) in _StringTypes:
            realY = realY.lower()

        result = 0
        if realX < realY:
            result = const * 1
        elif realX > realY:
            result = const * -1

        return result


class Report (Module):
    template_name = 'report.cs'
    template_rss_name = 'report_rss.cs'
    template_csv_name = 'report_csv.cs'

    def sql_sub_vars(self, sql, args):
        m = re.search(dynvars_re, sql)
        if not m:
            return sql
        aname=m.group()[1:]
        try:
            arg = args[aname]
        except KeyError:
            raise TracError("Dynamic variable '$%s' not defined." % aname)
        self.req.hdf.setValue('report.var.'+aname , arg)
        sql = m.string[:m.start()] + arg + m.string[m.end():]
        return self.sql_sub_vars(sql, args)
    
    def get_info(self, id, args):
        cursor = self.db.cursor()

        if id == -1:
            # If no particular report was requested, display
            # a list of available reports instead
            cursor.execute("SELECT id AS report, title "
                           "FROM report "
                           "ORDER BY report")
            title = 'Available reports'
            description = 'This is a list of reports available.'
        else:
            cursor.execute('SELECT title, sql, description from report '
                           ' WHERE id=%s', id)
            row = cursor.fetchone()
            try:
                if not row:
                    raise TracError('Report %d does not exist.' % id,
                                'Invalid Report Number')
                title = row[0] or ''
                sql   = self.sql_sub_vars(row[1], args)
                if not sql:
                    raise TracError('Report %s has no SQL query.' % id)
                description = row[2] or ''
                cursor.execute(sql)

                if sql.find('__group__') == -1:
                    self.req.hdf.setValue('report.sorting.enabled', '1')

            except Exception, e:
                self.error = e
                self.req.hdf.setValue('report.message',
                                      'report failed: %s' % e)
                return None

        # FIXME: fetchall should probably not be used.
        info = cursor.fetchall()
        cols = cursor.rs.col_defs
        # Escape the values so that they are safe to have as html parameters
#        info = map(lambda row: map(lambda x: escape(x), row), info)
        return [cols, info, title, description]
        
    def create_report(self, title, description, sql):
        self.perm.assert_permission(perm.REPORT_CREATE)

        cursor = self.db.cursor()
        cursor.execute('INSERT INTO report (id, title, sql, description)'
                        'VALUES (NULL, %s, %s, %s)', title, sql, description)
        id = self.db.db.sqlite_last_insert_rowid()
        self.db.commit()
        self.req.redirect(self.env.href.report(id))

    def delete_report(self, id):
        self.perm.assert_permission(perm.REPORT_DELETE)

        if self.args.has_key('delete'):
            cursor = self.db.cursor ()
            cursor.execute('DELETE FROM report WHERE id=%s', id)
            self.db.commit()
            self.req.redirect(self.env.href.report())
        else:
            self.req.redirect(self.env.href.report(id))

    def commit_changes(self, id):
        """
        saves report changes to the database
        """
        self.perm.assert_permission(perm.REPORT_MODIFY)

        cursor = self.db.cursor()
        title = self.args.get('title', '')
        sql   = self.args.get('sql', '')
        description   = self.args.get('description', '')

        cursor.execute('UPDATE report SET title=%s, sql=%s, description=%s '
                       ' WHERE id=%s',
                       title, sql, description, id)
        self.db.commit()
        self.req.redirect(self.env.href.report(id))

    def render_confirm_delete(self, id):
        self.perm.assert_permission(perm.REPORT_DELETE)
        cursor = self.db.cursor()

        cursor.execute('SELECT title FROM report WHERE id = %s', id)
        row = cursor.fetchone()
        if not row:
            raise TracError('Report %s does not exist.' % id,
                            'Invalid Report Number')
        self.req.hdf.setValue('title', '%s (report)' % row['title'])
        self.req.hdf.setValue('report.mode', 'delete')
        self.req.hdf.setValue('report.id', str(id))
        self.req.hdf.setValue('report.title', row['title'])

    def render_report_editor(self, id, action='commit', copy=0):
        self.perm.assert_permission(perm.REPORT_MODIFY)
        cursor = self.db.cursor()

        if id == -1:
            title = sql = description = ''
        else:
            cursor.execute('SELECT title, description, sql FROM report '
                           ' WHERE id=%s', id)
            row = cursor.fetchone()
            if not row:
                raise TracError('Report %s does not exist.' % id,
                                'Invalid Report Number')
            sql = row[2] or ''
            description = row[1] or ''
            title = row[0] or ''

        if copy:
            title += ' copy'
        
        self.req.hdf.setValue('report.mode', 'editor')
        self.req.hdf.setValue('report.title', title)
        self.req.hdf.setValue('report.id', str(id))
        self.req.hdf.setValue('report.action', action)
        self.req.hdf.setValue('report.sql', sql)
        self.req.hdf.setValue('report.description', description)

    def add_alternate_links(self, args):
        params = args
        if self.args.has_key('sort'):
            params['sort'] = self.args['sort']
        if self.args.has_key('asc'):
            params['asc'] = self.args['asc']
        href = ''
        if params:
            href = '&amp;' + urllib.urlencode(params).replace('&', '&amp;')
        self.add_link('alternate', '?format=rss' + href, 'RSS Feed',
            'application/rss+xml', 'rss')
        self.add_link('alternate', '?format=csv' + href,
            'Comma-delimited Text', 'text/plain')
        self.add_link('alternate', '?format=tab' + href,
            'Tab-delimited Text', 'text/plain')
        if self.perm.has_permission(perm.REPORT_SQL_VIEW):
            self.add_link('alternate', '?format=sql' + href, 'SQL Query',
                'text/plain')

    def render_report_list(self, id):
        """
        uses a user specified sql query to extract some information
        from the database and presents it as a html table.
        """
        if self.perm.has_permission(perm.REPORT_CREATE):
            self.req.hdf.setValue('report.create_href',
                                  self.env.href.report(None, 'new'))
            
        try:
            args = self.get_var_args()
        except ValueError,e:
            self.req.hdf.setValue('report.message', 'report failed: %s' % e)
            return
        
        if id != -1:
            self.add_alternate_links(args)
            if self.perm.has_permission(perm.REPORT_MODIFY):
                self.req.hdf.setValue('report.edit_href',
                                      self.env.href.report(id, 'edit'))
            if self.perm.has_permission(perm.REPORT_CREATE):
                self.req.hdf.setValue('report.copy_href',
                                      self.env.href.report(id, 'copy'))
            if self.perm.has_permission(perm.REPORT_DELETE):
                self.req.hdf.setValue('report.delete_href',
                                      self.env.href.report(id, 'delete'))

        self.req.hdf.setValue('report.mode', 'list')
        info = self.get_info(id, args)
        if not info:
            return
        [self.cols, self.rows, title, description] = info
        self.error = None
        
        self.req.hdf.setValue('title', title + ' (report)')
        self.req.hdf.setValue('report.title', title)
        self.req.hdf.setValue('report.id', str(id))
        descr_html = wiki_to_html(description, self.req.hdf, self.env)
        self.req.hdf.setValue('report.description', descr_html)

        # Convert the header info to HDF-format
        idx = 0
        for col in self.cols:
            title=col[0].capitalize()
            prefix = 'report.headers.%d' % idx
{'fraction_non_alphanumeric': 0.12054549074258411, 'fraction_numerical': 0.005624129006569779, 'mean_word_length': 1.888585393904543, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6293351', 'n_tokens_mistral': 5931, 'n_tokens_neox': 5784, 'n_words': 1488}