Ejemplo n.º 1
0
def main(argv=sys.argv):
    if len(argv) != 3:
        usage(argv)
    config_uri = argv[1]
    svn_csv = argv[2]
    setup_logging(config_uri)
    settings = get_appsettings(config_uri, name='dashboard')
    engine = engine_from_config(settings, 'sa.dashboard.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    Base.metadata.create_all()

    with transaction.manager:
        session = DBSession()
        with open(svn_csv, 'rb') as csvfile:
            reader = csv.reader(csvfile)
            for project_id, svn_repo in reader:
                svn_repo = svn_repo.strip()
                project_id = project_id.strip()
                project = session.query(Project).get(project_id)
                app = Application(name='SVN',
                                  project_id=project_id,
                                  application_type=SVN,
                                  svn_name=svn_repo)
                project.add_application(app)
                print 'Creating svn app [%s] for project [%s]' % (svn_repo, project_id)
Ejemplo n.º 2
0
def populate_dummies(settings=None):
    from penelope.core.models.dbsession import DBSession
    from penelope.core.models import Base

    if settings:
        engine = engine_from_config(settings, 'sa.dashboard.')
        DBSession.configure(bind=engine)
        Base.metadata.bind = engine

    Base.metadata.create_all()

    with transaction.manager:
        session = DBSession()
        users = [
            add_user(session, u'*****@*****.**', fullname='Administrator', password='******'),
        ]

        role_admin = add_role(session, 'administrator')
        role_admin.users.append(users[0])

        add_role(session, 'external_developer')
        add_role(session, 'internal_developer')
        add_role(session, 'secretary')
        add_role(session, 'customer')
        add_role(session, 'project_manager')

        session.add(GlobalConfig(id=1))
Ejemplo n.º 3
0
    def __call__(self, parser, namespace, values, option_string):
        super(QualityRaw, self).__call__(parser, namespace, values, option_string)
        session = DBSession()
        with open(namespace.filename, 'wb') as ofile:
            writer = csv.writer(ofile, dialect='excel')
            writer.writerow(['CR ID', 'Customer', 'Duration in days'])
            for cr in session.query(CustomerRequest.id,
                                    CustomerRequest.project_id,
                                    Project.customer_id,
                                    Trac.trac_name).\
                              outerjoin(Project,
                                        CustomerRequest.project_id == Project.id).\
                              outerjoin(Trac,
                                        Project.id==Trac.project_id).distinct():

                tickets, Ticket, TicketCustom = tickets_for_cr(self.metadata, session, cr.trac_name, cr.id)
                tids = [t.id for t in tickets]
                if not tids:
                    continue

                entries = session.query(TimeEntry)\
                                 .filter_by(project_id=cr.project_id)\
                                 .filter(TimeEntry.ticket.in_(tids))\
                                 .filter(extract('year', TimeEntry.date) == namespace.year)

                if entries.count():
                    hours = timedelta_as_work_days(sum([a.hours for a in entries], timedelta()))
                    writer.writerow([cr.id, cr.customer_id, hours])
Ejemplo n.º 4
0
 def on_mark_all_seen(self, data):
     user_id = data['user_id']
     session = DBSession()
     unseen = session.query(Activity)\
                     .filter_by(user_id=user_id)\
                     .filter_by(seen_at=None)
     now = datetime.now()
     for a in unseen:
         a.seen_at = now
     transaction.commit()
     r = redis.StrictRedis()
     r.publish('penelope:notifications:%s' % user_id, True)
Ejemplo n.º 5
0
def add_activity(user_ids, message, absolute_path, created_by=None):
    if created_by is None:
        created_by = '*****@*****.**'

    r = redis.StrictRedis()
    session = DBSession()
    for user_id in user_ids:
        activity = Activity(message=message,
                            created_at=datetime.now(),
                            user_id=user_id,
                            absolute_path=absolute_path,
                            created_by=created_by)

        session.add(activity)
        r.publish('penelope:notifications:%s' % user_id, True)
    transaction.commit()
Ejemplo n.º 6
0
    def __call__(self, parser, namespace, values, option_string):
        super(QualityTicket, self).__call__(parser, namespace, values, option_string)
        session = DBSession()
        with open(namespace.filename, 'wb') as ofile:
            writer = csv.writer(ofile, dialect='excel')
            writer.writerow(['Ticket ID', 'Customer',
                             'Ticket creation year',
                             'Ticket creation month',
                             'Ticket creation day',
                             'Ticket completion year',
                             'Ticket completion moneth',
                             'Ticket completion day',
                             'Ticket state', 'Ticket last owner', 'Ticket types',
                             'Ticket opened by customer', 'Problem nature'])

            for pr in session.query(Project.customer_id, Project.id, Trac.trac_name)\
                             .outerjoin(Trac, Project.id==Trac.project_id)\
                             .outerjoin(TimeEntry, TimeEntry.project_id==Project.id)\
                             .filter(TimeEntry.project_id==Project.id)\
                             .filter(extract('year', TimeEntry.date) == namespace.year).distinct():
                tickets, Ticket, TicketCustom = tickets_for_cr(self.metadata, session, pr.trac_name)
                tickets_in_year = session.query(Ticket)\
                                         .outerjoin(TimeEntry,
                                                    and_(TimeEntry.project_id==pr.id,
                                                         TimeEntry.ticket==Ticket.id))\
                                         .filter(extract('year', TimeEntry.date) == namespace.year).distinct()
                for ticket in tickets_in_year:
                    last_status = ticket.last_history('status', namespace.year)
                    close_date = ticket.close_date
                    all_types = set([])
                    for h in ticket.history:
                        if h.field == 'type':
                            all_types.update([h.oldvalue])
                    all_types.update([ticket.type])
                    all_types = '|'.join(all_types).encode('utf8','ignore')
                    writer.writerow(
                          [ticket.id, pr.customer_id,
                           ticket.date.strftime('%Y'),
                           ticket.date.strftime('%m'),
                           ticket.date.strftime('%d'),
                           close_date and close_date.strftime('%Y') or '',
                           close_date and close_date.strftime('%m') or '',
                           close_date and close_date.strftime('%d') or '',
                           last_status, ticket.owner, all_types,
                           ticket.open_by_customer and ticket.open_by_customer.unicode_value or '',
                           ticket.issue_type and ticket.issue_type.unicode_value or ''])
Ejemplo n.º 7
0
    def _get_activities_(self):
        session = DBSession()
        base_query = session.query(Activity)\
                            .filter_by(user_id=self.session['user_id'])
        count_unseen = base_query.filter_by(seen_at=None).count()
        activities = base_query.order_by(Activity.created_at.desc()).limit(5)

        response = []
        for activity in activities:
            response.append({'message': activity.message,
                             'unseen': activity.unseen,
                             'absolute_path': activity.absolute_path,
                             'created_by': activity.created_by,
                             'created_at': pretty.date(activity.created_at)})

        transaction.commit()
        return count_unseen, response
Ejemplo n.º 8
0
def unique(value, field=None):
    """Successful if value is unique"""
    msg = _('Broken ${value}', mapping={'value': value})
    if not field:
        raise ValidationError(msg)

    session = DBSession()

    filters = {}
    filters[field._column_name] = value
    records = session.query(field.model.__class__).filter_by(**filters)

    if records.count() > 0 and records.one() != field.model:
        msg = _("${value} already exists! Field '${field_column_name}' should be unique!",
                mapping={'value': value, 'field_column_name': field._column_name})
        raise ValidationError(msg)
    return value
Ejemplo n.º 9
0
    def __call__(self, parser, namespace, values, option_string):
        super(Quality, self).__init__(parser, namespace, values, option_string)
        self.namespace = namespace
        config_uri = namespace.configuration
        setup_logging(config_uri)
        settings = get_appsettings(config_uri, name='dashboard')
        engine = engine_from_config(settings, 'sa.dashboard.')
        DBSession.configure(bind=engine)
        Base.metadata.bind = engine
        Base.metadata.create_all()
        self.metadata = MetaData(engine)

        configuration = {}
        tmp = tempfile.NamedTemporaryFile(suffix='.csv')
        namespace.filename = tmp.name
        tmp.close()
        configuration['filename'] = namespace.filename
        print 'Creating file %s' % namespace.filename
        setattr(namespace, option_string.strip('--'), configuration)
Ejemplo n.º 10
0
    def __call__(self, parser, namespace, values, option_string):
        super(QualityCR, self).__call__(parser, namespace, values, option_string)
        session = DBSession()
        with open(namespace.filename, 'wb') as ofile:
            writer = csv.writer(ofile, dialect='excel')
            writer.writerow(['CR ID', 'Description', 'Customer', 'CR state',
                             'Estimation in days', 'TE duration in days - current year',
                             'TE sistem/install in days - current year',
                             'TE duration in days - overall', 'TE sistem/install in days - overall'])
            crs = session.query(CustomerRequest.id,
                                CustomerRequest.name,
                                CustomerRequest.workflow_state,
                                CustomerRequest.project_id,
                                Project.customer_id).\
                   outerjoin(Project, CustomerRequest.project_id == Project.id).distinct()

            for cr in crs:

                all_entries = session.query(TimeEntry).filter_by(customer_request_id=cr.id)
                if not all_entries.count():
                    continue

                estimations = sum([a.days for a in \
                                session.query(Estimation.days)\
                                       .filter_by(customer_request_id=cr.id)])

                current_year_entries = session.query(TimeEntry)\
                                              .filter_by(customer_request_id=cr.id)\
                                              .filter(extract('year', TimeEntry.date) == namespace.year)

                total_hours = timedelta_as_work_days(sum([a.hours for a in all_entries], timedelta()))
                total_dev_hours = timedelta_as_work_days(sum([a.hours for a in
                                            all_entries.filter(or_(TimeEntry.description.ilike('%install%'),
                                                                    TimeEntry.description.ilike('%sistem%')))], timedelta()))
                current_year_hours = timedelta_as_work_days(sum([a.hours for a in current_year_entries], timedelta()))
                current_year_dev_hours = timedelta_as_work_days(sum([a.hours for a in
                                                    current_year_entries.filter(or_(TimeEntry.description.ilike('%install%'),
                                                                                    TimeEntry.description.ilike('%sistem%')))], timedelta()))

                writer.writerow([cr.id, cr.name.encode('utf8'), cr.customer_id,
                    cr.workflow_state, estimations, current_year_hours,
                    current_year_dev_hours, total_hours, total_dev_hours])
Ejemplo n.º 11
0
    def __call__(self, parser, namespace, values, option_string):
        super(QualityProject, self).__call__(parser, namespace, values, option_string)
        session = DBSession()
        with open(namespace.filename, 'wb') as ofile:
            writer = csv.writer(ofile, dialect='excel')
            writer.writerow(['Project ID', 'Customer', 'Project creation year',
                             'Project creation month', 'Project creation day',
                             'Project completion year', 'Project completion month',
                             'Project completion day'])
            for project in session.query(Project.id, Project.completion_date,
                                   Project.customer_id, Project.creation_date)\
                                  .outerjoin(TimeEntry, TimeEntry.project_id==Project.id)\
                                  .filter(extract('year', TimeEntry.date) == namespace.year)\
                                  .distinct():

                writer.writerow([project.id, project.customer_id, 
                                 project.creation_date and project.creation_date.strftime('%Y') or '',
                                 project.creation_date and project.creation_date.strftime('%m') or '',
                                 project.creation_date and project.creation_date.strftime('%d') or '',
                                 project.completion_date and project.completion_date.strftime('%Y') or '',
                                 project.completion_date and project.completion_date.strftime('%m') or '',
                                 project.completion_date and project.completion_date.strftime('%d') or '',
                                 ])
Ejemplo n.º 12
0
def update_time_entries():
    session = DBSession()

    tracs = {}
    time_entries = session.query(TimeEntry)
    for tp in time_entries:
        trac = list(tp.project.tracs)[0]
        tracs.setdefault(trac.trac_name, [])
        if not tp.ticket:
            print "TimeEntry %s has no ticket" % tp.id
            continue
        tracs[trac.trac_name].append((tp.id, tp.ticket))

    ticket_vs_crs = """SELECT value AS cr_id, '%(tp_id)s' AS tp_id FROM "trac_%(trac)s".ticket_custom WHERE name='customerrequest' AND ticket=%(ticket)s"""
    splitted_tracs = split_dict_equally(tracs)

    for split in splitted_tracs:
        queries = []
        for trac_id, opts in split.items():
            for opt in opts:
                queries.append(ticket_vs_crs % {'trac': trac_id,
                                                'tp_id': opt[0],
                                                'ticket': opt[1]})
        sql = '\nUNION '.join(queries)
        sql += ';'
        for trac in DBSession().execute(sql).fetchall():
            cr = session.query(CustomerRequest).get(trac.cr_id)
            if not cr:
                continue
            contract = cr.contract
            if not contract:
                continue
            tp = session.query(TimeEntry).get(trac.tp_id)
            if not tp:
                continue
            tp.contract_id = contract.id
Ejemplo n.º 13
0
def add_svn_to_project(application):
    from penelope.core.models.dashboard import Project

    project = DBSession.query(Project).get(application.project_id)
    settings = get_current_registry().settings

    svnenvs = settings.get('penelope.svn.envs')
    tracenvs = settings.get('penelope.trac.envs')
    trac_admin = os.path.abspath('%s/../../bin/trac-admin' % tracenvs)

    if not os.path.exists(svnenvs):
        os.mkdir(svnenvs)

    svnname = application.svn_name
    if svnname:
        svn_path = '%s/%s' % (svnenvs, svnname)
        if not os.path.exists(svn_path):
            raise OSError, 'The path %s doesn\'t exists!' % svn_path
    else:
        idx = ''
        while (not svnname):
            svnname = idnormalizer.normalize("%s%s" % (project.id, idx))
            svn_path = '%s/%s' % (svnenvs, svnname)
            if os.path.exists(svn_path):
                idx = idx and (idx+1) or 1
                svnname = None

        _execute(['svnadmin', '--config-dir', '/etc/subversion', 'create', svn_path])

    for trac in project.tracs:
        tracname = str(trac.trac_name)
        trac_path = '%s/%s' % (tracenvs, tracname)
        run([trac_path, 'repository add %s %s' % (svnname, svn_path)])
        run([trac_path, 'repository resync %s' % (svnname)])
        run([trac_path, 'config set trac repository_sync_per_request ""'])

        hook_filename = '%s/hooks/post-commit' % svn_path
        with open(hook_filename, 'w') as hook:
            opts = {'trac_path': trac_path, 'trac_admin': trac_admin}
            hook.write(POST_COMMIT_HOOK % opts)
        st = os.stat(hook_filename)
        os.chmod(hook_filename, st.st_mode | stat.S_IEXEC)

    application.api_uri = 'svn://%s' % svnname
    application.svn_name = svnname
Ejemplo n.º 14
0
def initialize_sql(config=None, engine=None):
    if not engine:
        engine = engine_from_config(config.registry.settings, 'sa.dashboard.', poolclass=NullPool)
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
Ejemplo n.º 15
0
def main(argv=sys.argv):
    if len(argv) < 2:
        usage(argv)

    config_uri = argv[1]
    setup_logging(config_uri)
    env = bootstrap('%s#dashboard'% config_uri)
    settings = env.get('registry').settings
    engine = engine_from_config(settings, 'sa.dashboard.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine

    google_opts = argv[2:]
    try:
        google_user = google_opts.pop(0)
    except IndexError:
        google_user = raw_input('Google Spreadsheet User: '******'Google Spreadsheet ID: ')
    google_password = getpass.getpass("Google Spreadsheet Password: ")

    gc = gspread.login(google_user, google_password)
    sht = gc.open_by_key(spreadsheet_key)
    worksheet = sht.get_worksheet(0)
    crs = worksheet.get_all_records()

    contracts = {}
    for row in crs:
        if not row['titolocommessa']:
            continue
        contract_uid = '%s_%s_%s' % (row['project_name'],
                                     row['titolocommessa'],
                                     row['customer_id'])
        contracts.setdefault(contract_uid, {'crs': []})
        contracts[contract_uid]['titolocommessa'] = row['titolocommessa']
        contracts[contract_uid]['nrcontratto'] = row['nrcontratto']
        contracts[contract_uid]['gg'] = row['gg'] or 0
        contracts[contract_uid]['amount'] = row['amount'] or 0
        contracts[contract_uid]['crs'].append(row['cr_id'])
        contracts[contract_uid]['stato'] = map_state(row['stato'])

    # now we have a structure:
    # contracts['ContractUID'] = {'crs': ['customer_request_id_1',
    #                                     'customer_request_id_2'],
    #                             'gg': '12'}

    with transaction.manager:
        session = DBSession()
        for contract_uid, opts in contracts.items():
            crs = [session.query(CustomerRequest).get(a) for a in opts['crs']]
            crs = [a for a in crs if a]
            if not crs:
                continue
            contract = crs[0].contract
            if not contract:
                contract = Contract(name=opts['titolocommessa'])
            contract.days = opts['gg']
            contract.amount = opts['amount']
            contract.contract_number = opts['nrcontratto']
            contract.workflow_state = opts['stato']
            for cr in crs:
                if not cr:
                    continue
                cr.contract = contract
                contract.project_id = cr.project_id

        update_time_entries()
Ejemplo n.º 16
0
def add_trac_to_project(application,
        smtp_enabled=True,
        privatecomments=True,
        sensitivetickets=True,
        batchmod=True,
        autocompleteusers=True,
        customfieldadmin=True,
        qafields=True,
        privatetickets=False,
        tracwysiwyg=True,
        attachment_max_size=10485760,
        milestones=[],
        tickets=[],
        project_name=u'',
        ):

    from penelope.core.models.dashboard import Project

    project = DBSession.query(Project).get(application.project_id)

    settings = get_current_registry().settings or application.settings
    tracenvs = settings.get('penelope.trac.envs')

    if not os.path.exists(tracenvs):
        # TODO: logging bootstrap
        os.mkdir(tracenvs)

    tracname = None
    idx = ''
    while (not tracname):
        tracname = idnormalizer.normalize("%s%s" % (project.id, idx))
        trac_path = '%s/%s' % (tracenvs, tracname)
        if os.path.exists(trac_path):
            idx = idx and (idx+1) or 1
            tracname = None

    trac_perm = {
        'administrator': ['TRAC_ADMIN', 'EXTRA_TIMEENTRY'],
        'customer': ['TICKET_CREATE', 'TICKET_MODIFY', 'TICKET_VIEW',
            'WIKI_VIEW', 'XML_RPC',
            'CHANGESET_VIEW', 'FILE_VIEW',
            'LOG_VIEW', 'MILESTONE_VIEW',
            'REPORT_VIEW', 'REPORT_SQL_VIEW',
            'ROADMAP_VIEW', 'SEARCH_VIEW', 'TIMELINE_VIEW'],
        'developer': ['TICKET_CREATE', 'TICKET_MODIFY', 'TICKET_VIEW',
            'WIKI_VIEW', 'XML_RPC',
            'WIKI_CREATE', 'WIKI_MODIFY',
            'CHANGESET_VIEW', 'FILE_VIEW',
            'LOG_VIEW', 'MILESTONE_VIEW',
            'REPORT_VIEW', 'REPORT_SQL_VIEW',
            'ROADMAP_VIEW', 'SEARCH_VIEW',
            'TIMELINE_VIEW', 'REPORT_ADMIN'],
        'internal_developer': ['developer', 'TRAC_ADMIN', 'TIME_ENTRY_ADD'],
        'external_developer': ['developer'],
        'project_manager': ['administrator', 'TIME_ENTRY_ADD'],
    }


    pordb = str(DBSession.bind.url)
    run([trac_path, 'initenv "%s" "%s?schema=trac_%s"' % (
         tracname,
         pordb.replace('postgresql://', 'postgres://'),
         tracname)])

    tracenv = Environment(trac_path)

    # REPORTS
    cnx = tracenv.get_db_cnx().cnx
    cursor = cnx.cursor()
    cursor.executemany(\
        "INSERT INTO report (title, description, query) VALUES (%s, %s, %s)",
        get_reports(project_id=project.id))
    cursor.close()
    cnx.commit()

    # remove report 2
    cursor = cnx.cursor()
    cursor.execute("DELETE FROM report where id=2;")
    cursor.close()
    cnx.commit()

    # update reports
    cursor = cnx.cursor()
    cursor.execute("""UPDATE report set query='
        SELECT p.value AS __color__,
            t.id AS ticket, summary, t.type AS type, cr.name AS CR,
            owner, status,
            time AS created,
            changetime AS _changetime, t.description AS _description,
            reporter AS _reporter
        FROM ticket t
        LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority''
        LEFT JOIN ticket_custom tc ON t.id = tc.ticket
        LEFT JOIN public.customer_requests cr ON tc.value = cr.id
        WHERE status <> ''closed''
        AND tc.name = ''customerrequest''
        ORDER BY CAST(p.value AS int), milestone, t.type, time' where id=1;""")
    cursor.execute("""UPDATE report set query='
            SELECT p.value AS __color__,
               ''Milestone ''||milestone AS __group__,
               t.id AS ticket, summary, t.type AS type,
               cr.name AS CR,
               owner, status,
               time AS created,
               changetime AS _changetime, t.description AS _description,
               reporter AS _reporter
            FROM ticket t
            LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority''
            LEFT JOIN ticket_custom tc ON t.id = tc.ticket
            LEFT JOIN public.customer_requests cr ON tc.value = cr.id
            WHERE status <> ''closed''
            AND tc.name = ''customerrequest''
            ORDER BY (milestone IS NULL),milestone, CAST(p.value AS int), t.type, time' where id=3;""")
    cursor.execute("""UPDATE report set query='
            SELECT p.value AS __color__,
               owner AS __group__,
               t.id AS ticket, summary, milestone,  cr.name AS CR, t.type AS type, time AS created,
               changetime AS _changetime, t.description AS _description,
               reporter AS _reporter
            FROM ticket t
            LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority''
            LEFT JOIN ticket_custom tc ON t.id = tc.ticket
            LEFT JOIN public.customer_requests cr ON tc.value = cr.id
            WHERE status = ''accepted''
            AND tc.name = ''customerrequest''
            ORDER BY owner, CAST(p.value AS int), t.type, time'
            where id=4;""")
    cursor.execute("""UPDATE report set query='
            SELECT p.value AS __color__,
               owner AS __group__,
               t.id AS ticket, summary, milestone, t.type AS type, cr.name AS CR, time AS created,
               t.description AS _description_,
               changetime AS _changetime, reporter AS _reporter
            FROM ticket t
            LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority''
            LEFT JOIN ticket_custom tc ON t.id = tc.ticket
            LEFT JOIN public.customer_requests cr ON tc.value = cr.id
            WHERE status = ''accepted''
            AND tc.name = ''customerrequest''
            ORDER BY owner, CAST(p.value AS int), t.type, time'
            where id=5;""")
    cursor.execute("""UPDATE report set query='
            SELECT p.value AS __color__,
            (CASE status WHEN ''accepted'' THEN ''Accepted'' ELSE ''Owned'' END) AS __group__,
                 t.id AS ticket, summary, milestone, cr.name AS CR,
                 t.type AS type, priority, time AS created,
                 changetime AS _changetime, t.description AS _description,
                 reporter AS _reporter
            FROM ticket t
            LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority''
            LEFT JOIN ticket_custom tc ON t.id = tc.ticket
            LEFT JOIN public.customer_requests cr ON tc.value = cr.id
            WHERE t.status <> ''closed'' AND owner = $USER
            AND tc.name = ''customerrequest''
            ORDER BY (status = ''accepted'') DESC, CAST(p.value AS int), milestone, t.type, time'
            where id=7;""")
    cursor.execute("""UPDATE report set query='
            SELECT p.value AS __color__,
           (CASE owner
            WHEN $USER THEN ''My Tickets''
                ELSE ''Active Tickets''
            END) AS __group__,
                t.id AS ticket, summary, milestone, t.type AS type, cr.name AS CR,
                owner, status,
                time AS created,
                changetime AS _changetime, t.description AS _description,
                reporter AS _reporter
            FROM ticket t
            LEFT JOIN enum p ON p.name = t.priority AND p.type = ''priority''
            LEFT JOIN ticket_custom tc ON t.id = tc.ticket
            LEFT JOIN public.customer_requests cr ON tc.value = cr.id
            WHERE status <> ''closed''
            AND tc.name = ''customerrequest''
            ORDER BY (COALESCE(owner, '''') = $USER) DESC, CAST(p.value AS int), milestone, t.type, time'
            where id=8;""")
    cursor.close()
    cnx.commit()

    # remove default trac's milestones, components, versions
    cursor = cnx.cursor()
    cursor.execute("DELETE FROM milestone;")
    cursor.close()
    cnx.commit()

    cursor = cnx.cursor()
    cursor.execute("DELETE FROM component;")
    cursor.close()
    cnx.commit()

    cursor = cnx.cursor()
    cursor.execute("DELETE FROM version;")
    cursor.close()
    cnx.commit()


    # TODO: attualmente il riferimento dal trac al progetto dashboard è il project_id,
    #       considerando un'instalalzzione che condicide lo stesso stack wsgi,
    #       valutare se deve essere una uri (jsnorpc, xmlrpx, ...)
    #       o un dsn che punti al db, o ...
    tracenv.config.set('por-dashboard', 'project-id', application.project_id)

    # custom templates
    templates = settings.get('penelope.trac.templates')
    masterconfig = settings.get('penelope.trac.masterconfig')

    if templates:
        tracenv.config.set('inherit', 'templates_dir', templates)

    # master config
    if masterconfig:
        tracenv.config.set('inherit', 'file', masterconfig)

    # set name and description
    tracenv.config.set('project', 'name', project_name)
    tracenv.config.set('project', 'descr', application.name)

    tracenv.config.set('notification', 'smtp_enabled', smtp_enabled and 'true' or 'false')
    tracenv.config.set('notification', 'always_notify_owner', 'true')
    tracenv.config.set('notification', 'always_notify_reporter', 'true')
    manager_email = project.manager.email or ''
    tracenv.config.set('notification', 'smtp_always_cc', manager_email) # manager should always receiv CC

    tracenv.config.set('attachment', 'max_size', attachment_max_size)

    tracenv.config.set('components', 'penelope.trac.*', 'enabled')
    tracenv.config.set('components', 'themeengine.admin.*', 'enabled')
    tracenv.config.set('components', 'themeengine.api.*', 'enabled')
    tracenv.config.set('components', 'themeengine.web_ui.*', 'enabled')
    tracenv.config.set('components', 'ticketrelations.*', 'enabled')
    tracenv.config.set('components', 'tracopt.perm.config_perm_provider.extrapermissionsprovider', 'enabled')

    # All the custom permission names are converted to uppercase.
    # It is not possible to have lowercase and distinguish them from the standard permissions.
    tracenv.config.set('extra-permissions', 'extra_timeentry', 'TIME_ENTRY_ADD')

    tracenv.config.set('theme','theme', 'por')
    # ticket-custom
    tracenv.config.set('ticket-custom', 'customerrequest', 'select')
    tracenv.config.set('ticket-custom', 'customerrequest.label', 'Customer Request')
    tracenv.config.set('ticket-custom', 'blocking', 'text')
    tracenv.config.set('ticket-custom', 'blocking.label', 'Blocking')
    tracenv.config.set('ticket-custom', 'blockedby', 'text')
    tracenv.config.set('ticket-custom', 'blockedby.label', 'Blocked By')
    # BBB: ii valori di customerrequest vengono caricati ondemand
    tracenv.config.set('ticket-custom', 'customerrequest.options', '')

    # see ticket:80
    if qafields:
        tracenv.config.set('ticket-custom', 'issuetype', 'select')
        tracenv.config.set('ticket-custom', 'issuetype.label', 'Natura del problema')
        tracenv.config.set('ticket-custom', 'issuetype.options', '|'.join([u"",
                                u"sistemistica",
                                u"funzionalità",
                                u"design (grafica, layout...)",
                                u"prestazioni",
                                u"mi aspettavo che..."]))
        tracenv.config.set('ticket-custom', 'esogeno', 'checkbox')
        tracenv.config.set('ticket-custom', 'esogeno.label', 'Ticket aperto dal Cliente')
        tracenv.config.set('ticket-custom', 'esogeno.value', 'false')
        tracenv.config.set('ticket-custom', 'stats_exclude', 'checkbox')
        tracenv.config.set('ticket-custom', 'stats_exclude.label', 'Exclude from report stats')
        tracenv.config.set('ticket-custom', 'stats_exclude.value', 'false')
        tracenv.config.set('ticket-custom', 'fasesviluppo', 'select')
        tracenv.config.set('ticket-custom', 'fasesviluppo.label', 'Fase sviluppo')
        tracenv.config.set('ticket-custom', 'fasesviluppo.options', '|'.join([u"",
                                u"In lavorazione",
                                u"Per lo staging",
                                u"In staging",
                                u"Per la produzione",
                                u"In produzione"]))

    tracenv.config.set('ticket', 'restrict_owner', 'true')

    tracenv.config.set('ticket-custom', 'milestone.invalid_if', '')

    # WORKFLOW
    tracenv.config.set('ticket-workflow', 'accept', 'new,reviewing -> assigned')
    tracenv.config.set('ticket-workflow', 'accept.operations', 'set_owner_to_self')
    tracenv.config.set('ticket-workflow', 'accept.permissions', 'TICKET_MODIFY')
    tracenv.config.set('ticket-workflow', 'leave', '* -> *')
    tracenv.config.set('ticket-workflow', 'leave.default', '1')
    tracenv.config.set('ticket-workflow', 'leave.operations', 'leave_status')
    tracenv.config.set('ticket-workflow', 'reassign', 'new,assigned,accepted,reopened -> assigned')
    tracenv.config.set('ticket-workflow', 'reassign.operations', 'set_owner')
    tracenv.config.set('ticket-workflow', 'reassign.permissions', 'TICKET_MODIFY')
    tracenv.config.set('ticket-workflow', 'reassign_reviewing', 'reviewing -> *')
    tracenv.config.set('ticket-workflow', 'reassign_reviewing.name', 'reassign review')
    tracenv.config.set('ticket-workflow', 'reassign_reviewing.operations', 'set_owner')
    tracenv.config.set('ticket-workflow', 'reassign_reviewing.permissions', 'TICKET_MODIFY')
    tracenv.config.set('ticket-workflow', 'reopen', 'closed -> reopened')
    tracenv.config.set('ticket-workflow', 'reopen.operations', 'del_resolution')
    tracenv.config.set('ticket-workflow', 'reopen.permissions', 'TRAC_ADMIN')
    tracenv.config.set('ticket-workflow', 'resolve', 'new,assigned,reopened,reviewing -> closed')
    tracenv.config.set('ticket-workflow', 'resolve.operations', 'set_resolution')
    tracenv.config.set('ticket-workflow', 'resolve.permissions', 'TICKET_MODIFY')
    tracenv.config.set('ticket-workflow', 'review', 'new,assigned,reopened -> reviewing')
    tracenv.config.set('ticket-workflow', 'review.operations', 'set_owner')
    tracenv.config.set('ticket-workflow', 'review.permissions', 'TICKET_MODIFY')

    tracenv.config.set('milestone-groups', 'closed', 'closed')
    tracenv.config.set('milestone-groups', 'closed.order', '0')
    tracenv.config.set('milestone-groups', 'closed.query_args', 'group=resolution')
    tracenv.config.set('milestone-groups', 'closed.overall_completion', 'true')

    tracenv.config.set('milestone-groups', 'active', '*')
    tracenv.config.set('milestone-groups', 'active.order', '1')
    tracenv.config.set('milestone-groups', 'active.css_class', 'open')

    tracenv.config.set('milestone-groups', 'new', 'new,reopened')
    tracenv.config.set('milestone-groups', 'new.order', '2')


    # navigation
    tracenv.config.set('metanav', 'logout', 'disabled')

    # permissions
    tracenv.config.set('components', 'penelope.trac.users.*', 'enabled')
    tracenv.config.set('trac', 'permission_store', 'PorPermissionStore')
    tracenv.config.set('trac', 'show_email_addresses', 'true')

    # xmlrpc plugin
    tracenv.config.set('components', 'tracrpc.api.xmlrpcsystem', 'enabled')
    tracenv.config.set('components', 'tracrpc.xml_rpc.xmlrpcprotocol', 'enabled')
    tracenv.config.set('components', 'tracrpc.web_ui.rpcweb', 'enabled')
    tracenv.config.set('components', 'tracrpc.ticket.*', 'enabled')

    # DynamicFields Plugin
    tracenv.config.set('components', 'dynfields.rules.*','enabled')
    tracenv.config.set('components', 'dynfields.web_ui.*','enabled')

    # User & Roles (ReadOnly !!!)
    # tracenv.config.set('user_manager', 'user_store', 'PorUserStore')
    # tracenv.config.set('user_manager', 'attribute_provider', 'PorAttributeProvider')

    # BatchModifyPlugin
    if batchmod:
        tracenv.config.set('components', 'batchmod.web_ui.*', 'enabled')

    # Traccustomfieldadmin
    if customfieldadmin:
        tracenv.config.set('components', 'customfieldadmin.*', 'enabled')

    # PrivateCommentsPlugin
    if privatecomments:
        tracenv.config.set('components', 'privatecomments.privatecomments.*', 'enabled')

    # PrivateTicketPlugin
    if privatetickets:
        tracenv.config.set('components', 'privatetickets.policy.*', 'enabled')
        tracenv.config.set('trac', 'permission_policies',
            'PrivateTicketsPolicy, %s' % tracenv.config.get('trac', 'permission_policies'))
        trac_perm['customer'].append('TICKET_VIEW_SELF')

    # SensitiveTicketsPlugin
    if sensitivetickets:
        tracenv.config.set('components', 'sensitivetickets.*', 'enabled')
        tracenv.config.set('trac', 'permission_policies',
            'SensitiveTicketsPolicy, %s' % tracenv.config.get('trac', 'permission_policies'))
        tracenv.config.set('ticket-custom', 'sensitive.show_if_group', 'administrator|developer')
        # utilizzato se il default e' 1, se il default e' 0 non serve
        # tracenv.config.set('ticket-custom', 'sensitive.clear_on_hide', 'false')
        # tracenv.config.set('ticket-custom', 'sensitive.has_permission', 'SENSITIVE_VIEW')
        tracenv.config.set('ticket-custom', 'sensitive.value', '0')
        trac_perm['developer'].append('SENSITIVE_VIEW')

    # tracwysiwyg
    if tracwysiwyg:
        tracenv.config.set('components', 'tracwysiwyg.wysiwygmodule', 'enabled')

    # AutoCompleteUsers
    if autocompleteusers:
        tracenv.config.set('components', 'autocompleteusers.autocompleteusers', 'enabled')

    tracenv.config.set('wiki', 'max_size', 1048576)

    tracenv.config.set('logging', 'log_file', 'trac.log')
    tracenv.config.set('logging', 'log_level', 'INFO')
    tracenv.config.set('logging', 'log_type', 'file')

    tracenv.config.save()

    # let's remove notification config - it is set by the global config
    tracenv.config.remove('notification', 'smtp_from')
    tracenv.config.remove('notification', 'smtp_from_name')
    tracenv.config.remove('notification', 'replyto')
    tracenv.config.remove('notification', 'smtp_replyto')
    tracenv.config.remove('notification', 'email_sender')
    tracenv.config.remove('notification', 'smtp_enabled')
    tracenv.config.remove('notification', 'smtp_host')
    tracenv.config.remove('notification', 'smtp_port')
    tracenv.config.remove('notification', 'smtp_password')
    tracenv.config.remove('notification', 'smtp_username')

    tracenv.config.remove('trac', 'repository_sync_per_request')
    tracenv.config.save()

    run([trac_path, 'upgrade --no-backup'])

    run([trac_path, 'permission remove anonymous *'])
    run([trac_path, 'permission remove authenticated *'])
    for role, perms in trac_perm.items():
        for perm in perms:
            run([trac_path, "permission add %s %s" % (role, perm)])

    run([trac_path, "ticket_type add verification"])

    # hack to minimize config size
    run([trac_path, 'config set browser color_scale True'])

    # add properly milestones
    milestones.append({'title': 'Backlog', 'due_date': date.today().replace(year=date.today().year+1)})

    for milestone in milestones:
        due = milestone['due_date']
        if due:
            due = milestone['due_date'].strftime('%Y-%m-%d')
            run([trac_path, 'milestone add "%s" %s' % (milestone['title'], due)])
        else:
            run([trac_path, 'milestone add "%s"' % milestone['title']])

    tracenv = Environment(trac_path)
    for ticket in tickets:
        # in this moment the customer request has a proper id
        ticket['status'] = 'new'
        t = Ticket(tracenv)
        t.populate(ticket)
        t.insert()

    application.api_uri = 'trac://%s' % tracname
    application.trac_name = tracname
Ejemplo n.º 17
0
    def __call__(self, parser, namespace, values, option_string):
        super(QualityOperator, self).__call__(parser, namespace, values, option_string)
        session = DBSession()
        with open(namespace.filename, 'wb') as ofile:
            writer = csv.writer(ofile, dialect='excel')

            writer.writerow(['Customer name', 'Project name', 'CR description', 'CR total estimations (days)', 'CR status',
                             'Contract number', 'Contract amount', 'Contract days', 'Contract end date', 'Contract status',
                             'User', 'Total time in CR (days)'])
            query = session.query(
                                  TimeEntry.customer_request_id,
                                  TimeEntry.author_id,
                                  func.sum(TimeEntry.hours).label('total_time'),
                                  CustomerRequest,
                                  Project.name.label('project'),
                                  Customer.name.label('customer'),
                                  Contract.amount.label('contract_amount'),
                                  Contract.days.label('contract_days'),
                                  Contract.contract_number,
                                  Contract.end_date.label('contract_end_date'),
                                  Contract.workflow_state.label('contract_workflow_state'),
                                  User.fullname.label('user'),
                                  )\
                           .options(defer(CustomerRequest.filler),
                                    defer(CustomerRequest.old_contract_name),
                                    defer(CustomerRequest.uid),
                                    defer(CustomerRequest.description),
                                    defer(CustomerRequest.project_id),
                                    defer(CustomerRequest.contract_id),
                                   )\
                           .join(CustomerRequest)\
                           .join(Project)\
                           .join(Customer)\
                           .join(Contract, and_(TimeEntry.customer_request_id==CustomerRequest.id,
                                                CustomerRequest.contract_id==Contract.id))\
                           .outerjoin(User, TimeEntry.author_id==User.id)\
                           .filter(extract('year', TimeEntry.date) == namespace.year)\
                           .group_by(TimeEntry.customer_request_id)\
                           .group_by(TimeEntry.author_id)\
                           .group_by(Project.name)\
                           .group_by(Contract.amount)\
                           .group_by(Contract.contract_number)\
                           .group_by(Contract.days)\
                           .group_by(Contract.end_date)\
                           .group_by(Contract.workflow_state)\
                           .group_by(CustomerRequest.name)\
                           .group_by(CustomerRequest.id)\
                           .order_by(CustomerRequest.name)\
                           .order_by(CustomerRequest.workflow_state)\
                           .group_by(Customer.name)\
                           .group_by(User.fullname)

            for row in query:
                writer.writerow([row.customer.encode('utf8'),
                                 row.project.encode('utf8'),
                                 row.CustomerRequest.name.encode('utf8'),
                                 row.CustomerRequest.estimation_days,
                                 row.CustomerRequest.workflow_state,
                                 row.contract_number and row.contract_number.encode('utf8') or 'N/A',
                                 row.contract_amount or 0,
                                 row.contract_days or 0,
                                 row.contract_end_date or 'N/A',
                                 row.contract_workflow_state,
                                 row.user.encode('utf8'),
                                 timedelta_as_work_days(row.total_time)])
Ejemplo n.º 18
0
    def __call__(self, parser, namespace, values, option_string):
        super(QualityOurCustomerTime, self).__call__(parser, namespace, values, option_string)
        session = DBSession()

        def is_rt_user(email):
            return email and 'redturtle' in email or False

        def round_to(n, precission):
            correction = 0.5 if n >= 0 else -0.5
            return int(n/precission+correction)*precission

        def elapsed_time_in_minutes(start, end):
            td = from_utimestamp(end) - from_utimestamp(start)
            total_seconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
            return round_to((total_seconds / 3600.0), 0.5)

        def url(ticket):
            return "https://penelope.redturtle.it/trac/{0.trac}/ticket/{0.id}".format(ticket)

        query = """SELECT '{0}' AS trac,
                          '{2}' AS project,
                          '{3}' AS customer,
                          id,
                          time,
                          changetime,
                          owner,
                          reporter,
                          summary,
                          type,
                          customerrequest.value AS cr_id,
                          exclude_stats.value AS excluded
                    FROM "trac_{0}".ticket AS ticket
                    LEFT OUTER JOIN "trac_{0}".ticket_custom AS customerrequest ON ticket.id=customerrequest.ticket AND customerrequest.name='customerrequest'
                    LEFT OUTER JOIN "trac_{0}".ticket_custom AS exclude_stats ON ticket.id=exclude_stats.ticket AND exclude_stats.name='stats_exclude'
                        WHERE status='closed'
                        AND EXTRACT('year' FROM to_timestamp(changetime / 1000000)) = {1}"""

        crs = dict(session.query(CustomerRequest.id, CustomerRequest.name).all())
        queries = []
        for trac in session.query(Trac):
            queries.append(query.format(trac.trac_name, namespace.year, trac.project.name.replace("'","''"), trac.project.customer.name.replace("'","''")))
        sql = '\nUNION '.join(queries)
        sql += ';'

        with open(namespace.filename, 'wb') as ofile:
            writer = csv.writer(ofile, dialect='excel')

            writer.writerow(['Customer', 'Project', 'CR ID', 'CR name', 'Ticket #', 'Ticket summary', 'Ticket type', 'Ticket URL', 'Owner', 'Is RedTurtle user', 'Elapsed time (in normal hours)', 'Excluded from stats'])

            for ticket in session.execute(sql).fetchall():
                reporter = ticket.reporter
                owner = ticket.owner or reporter
                history = session.execute("""SELECT time, oldvalue, newvalue 
                                                FROM "trac_{0}".ticket_change
                                                    WHERE ticket={1} AND field='owner'
                                                    ORDER BY time""".format(ticket.trac, ticket.id)).fetchall()
                if not history:
                    writer.writerow([ticket.customer, ticket.project, ticket.cr_id, crs.get(ticket.cr_id), ticket.id, ticket.summary, ticket.type, url(ticket), owner, is_rt_user(owner), elapsed_time_in_minutes(ticket.time, ticket.changetime), ticket.excluded])
                else:
                    first_history = history.pop(0)
                    owner = first_history.oldvalue or reporter
                    last_change = first_history.time
                    writer.writerow([ticket.customer, ticket.project, ticket.cr_id, crs.get(ticket.cr_id), ticket.id, ticket.summary, ticket.type, url(ticket), owner, is_rt_user(owner), elapsed_time_in_minutes(ticket.time, last_change), ticket.excluded])

                    for h in history:
                        owner = h.oldvalue or reporter
                        writer.writerow([ticket.customer, ticket.project, ticket.cr_id, crs.get(ticket.cr_id), ticket.id, ticket.summary, ticket.type, url(ticket), owner, is_rt_user(owner), elapsed_time_in_minutes(last_change, h.time), ticket.excluded])
                        last_change = h.time