Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Upload downloads to the repo (github deprecated downloads)

  • Loading branch information...
commit e6ef9da201d4b9008ae1d06bad316721e7b7fcda 1 parent 3dbf43d
@lexqt authored
View
9 downloads/README.md
@@ -0,0 +1,9 @@
+# Downloads
+
+* **trac.wsgi** - WSGI script
+* **trac-svn-hooks.tar.gz** - SVN hooks
+* **trac.ini** - Example EduTrac configuration
+* **id2.ini** - Example syllabus configuration *[Russian]*
+* **\_\_init__.py** — Evaluation package example: \_\_init__ exports Model class
+* **model.py** — Evaluation package example: module with model, variables and constants *[Russian]*
+* **simple_model.tar.gz** — Evaluation package example: archive format
View
1  downloads/__init__.py
@@ -0,0 +1 @@
+from .model import Model
View
239 downloads/id2.ini
@@ -0,0 +1,239 @@
+# -*- coding: utf-8 -*-
+
+[components]
+ganttcalendar.ticketcalendar.ticketcalendar = disabled
+worklog.* = disabled
+
+[evaluation]
+package = simple_model
+
+[evaluation-constants]
+exp_learning_objectives = 0.3
+exp_project_completion = 0.7
+final_individual_weight = 0.5
+final_project_weight = 0.5
+indiv_earned_weight = 0.5
+indiv_peer_weight = 0.5
+project_completion = 0.1
+project_expert = 0.5
+project_milestones = 0.4
+test_bool_constant = True
+
+[ganttcalendar]
+complete_conditions = done, outdated, invalid
+
+[inherit]
+file = ../trac.ini
+
+[mastertickets]
+bad_closed_resolution = invalid, outdated
+check_action = wait_team, team_self_accept, team_check_accept
+
+[milestone-groups]
+active = *
+active.css_class = inprogress
+active.label = В работе
+active.order = 1
+closed = closed
+closed.label = Закрытые
+closed.order = 0
+closed.overall_completion = true
+closed.query_args = group=resolution
+new = new,approved
+new.label = Новые
+new.order = 2
+new.query_args = group=reporter
+
+[team-calendar]
+weeks_after = 1
+weeks_prior = 1
+
+[ticket]
+commit_ticket_all_refs = true
+commit_ticket_allow_commands = false
+commit_ticket_update_check_perms = true
+commit_ticket_update_commands.close.resolution =
+commit_ticket_update_commands.close.status = waiting_team
+commit_ticket_update_notify = true
+
+[ticket-custom]
+blockedby = text
+blockedby.label = Блокируется
+blockedby.order = 2
+blocking = text
+blocking.label = Блокирует
+blocking.order = 3
+complete = int
+complete.label = Завершено [%]
+complete.optional = false
+complete.order = 10
+complete.value = 0
+due_assign = date
+due_assign.label = Дата начала
+due_assign.optional = false
+due_assign.order = 8
+due_close = date
+due_close.label = Крайний срок
+due_close.optional = false
+due_close.order = 9
+estimatedhours = float
+estimatedhours.label = Оценка трудоемкости в часах
+estimatedhours.order = 4
+estimatedhours.value = 0
+hours = float
+hours.hide_view = true
+hours.label = Добавить отработанные часы
+hours.order = 5
+hours.value = 0.0
+hours.virtual = true
+modifier = int
+modifier.label = Модификатор стоимости
+modifier.order = 1
+modifier.value = 0
+totalhours = float
+totalhours.label = Затрачено часов
+totalhours.order = 5
+totalhours.value = 0
+
+[ticket-fields]
+milestone.optional = false
+priority.value = второстепенная
+severity.value = обычная
+type.value = программирование
+
+[ticket-fields-filters]
+estimatedhours.permission = TIME_RECORD:disable
+fields = totalhours, hours, estimatedhours
+hours.permission = TIME_VIEW:remove, TIME_RECORD:disable
+totalhours.disable = true
+
+[ticket-workflow]
+approve = new -> approved
+approve.name = утвердить
+approve.operations = del_owner
+approve.permissions = TICKET_MODIFY,TICKET_APPROVE
+assign = approved -> assigned
+assign.name = назначить исполнителя
+assign.operations = set_owner, notify_owner
+assign.owner_realm = team
+assign.permissions = TICKET_MODIFY,TICKET_ASSIGN
+cancel_assign = assigned -> approved
+cancel_assign.name = отменить исполнение
+cancel_assign.operations = del_owner, del_resolution, notify_owner
+cancel_assign.permissions = TICKET_MODIFY,TICKET_ASSIGN
+change_owner = * -> *
+change_owner.default = -10
+change_owner.name = сменить владельца
+change_owner.operations = set_owner, notify_owner
+change_owner.permissions = TICKET_ADMIN
+close_as = approved, assigned -> closed
+close_as.name = закрыть
+close_as.operations = set_resolution, notify_owner
+close_as.permissions = TICKET_MODIFY,TICKET_APPROVE
+close_as.set_resolution = invalid, outdated
+close_new = new -> closed
+close_new.name = закрыть
+close_new.operations = set_resolution
+close_new.permissions = TICKET_MODIFY,TICKET_CLOSE_NEW
+close_new.set_resolution = outdated, invalid
+comment = * -> *
+comment.default = 10
+comment.name = оставить комментарий
+comment.operations = comment
+comment.permissions = TICKET_APPEND
+comment_notify = * -> *
+comment_notify.default = 9
+comment_notify.name = оставить комментарий и уведомить
+comment_notify.notify = true
+comment_notify.operations = comment
+comment_notify.permissions = TICKET_APPEND
+comment_notify.user_realm = team|manager
+correct = assigned, waiting_team -> *
+correct.default = 15
+correct.name = корректировать
+correct.operations = leave_status
+correct.permissions = TICKET_MODIFY,TICKET_IS_OWNER
+correct_approved = approved -> approved
+correct_approved.name = корректировать
+correct_approved.operations = leave_status
+correct_approved.permissions = TICKET_MODIFY,TICKET_APPROVE
+invalidate = closed -> closed
+invalidate.default = -5
+invalidate.name = отметить как невалидную
+invalidate.operations = set_resolution, notify_owner
+invalidate.permissions = TICKET_ADMIN
+invalidate.set_resolution = invalid
+leave_closed = closed -> closed
+leave_closed.default = 5
+leave_closed.name = оставить статус
+leave_closed.operations = leave_status
+leave_closed.permissions = TICKET_MODIFY,TICKET_MODIFY_CLOSED
+leave_new = new -> new
+leave_new.default = 15
+leave_new.name = оставить статус
+leave_new.operations = leave_status
+leave_new.permissions = TICKET_MODIFY
+leave_status = * -> *
+leave_status.default = 20
+leave_status.name = оставить статус
+leave_status.operations = leave_status
+leave_status.permissions = TICKET_ADMIN
+man_accept = assigned -> closed
+man_accept.default = 7
+man_accept.name = принять и закрыть
+man_accept.operations = set_resolution, notify_owner
+man_accept.permissions = TICKET_MODIFY,TICKET_MAN_CHECK
+man_accept.set_resolution = done, invalid, outdated
+notify_new = new -> new
+notify_new.default = 8
+notify_new.name = уведомить о задаче
+notify_new.operations = set_owner, notify_owner
+notify_new.owner_realm = team|manager
+notify_new.permissions = TICKET_MODIFY
+outdate = assigned -> closed
+outdate.name = отметить как неактуальную
+outdate.operations = set_resolution
+outdate.permissions = TICKET_MODIFY,TICKET_IS_OWNER
+outdate.set_resolution = outdated
+reassign = assigned -> assigned
+reassign.name = переназначить исполнителя
+reassign.operations = set_owner, set_resolution
+reassign.permissions = TICKET_MODIFY,TICKET_ASSIGN
+reassign.set_resolution = reassigned
+reopen = closed -> assigned
+reopen.name = открыть заново
+reopen.operations = set_resolution, notify_owner
+reopen.permissions = TICKET_MODIFY,TICKET_REOPEN
+reopen.set_resolution = incomplete
+self_assign = approved -> assigned
+self_assign.name = назначить себя исполнителем
+self_assign.operations = set_owner_to_self
+self_assign.permissions = TICKET_MODIFY,TICKET_SELF_ASSIGN
+team_check_accept = waiting_team -> closed
+team_check_accept.name = принять и закрыть
+team_check_accept.operations = set_previous_owner, set_resolution, notify_owner
+team_check_accept.permissions = TICKET_MODIFY,TICKET_IS_OWNER,TICKET_TEAM_CHECK
+team_check_accept.set_resolution = done
+team_check_reject = waiting_team -> assigned
+team_check_reject.name = отклонить и отправить на доработку
+team_check_reject.operations = set_previous_owner, set_resolution, notify_owner
+team_check_reject.permissions = TICKET_MODIFY,TICKET_IS_OWNER,TICKET_TEAM_CHECK
+team_check_reject.set_resolution = incomplete
+team_self_accept = assigned -> closed
+team_self_accept.default = 7
+team_self_accept.name = принять и закрыть
+team_self_accept.operations = set_resolution, notify_owner
+team_self_accept.permissions = TICKET_MODIFY,TICKET_IS_OWNER,TICKET_TEAM_CHECK
+team_self_accept.set_resolution = done
+wait_team = assigned -> waiting_team
+wait_team.default = 6
+wait_team.name = отправить на проверку тим-лидеру
+wait_team.operations = set_owner, del_resolution, notify_owner
+wait_team.owner_perm_group = TeamLeader
+wait_team.owner_realm = team
+wait_team.permissions = TICKET_MODIFY,TICKET_IS_OWNER,!TICKET_TEAM_CHECK
+
+[ticket-workflow-config]
+busy_status = assigned
+max_busy = 20
+
View
812 downloads/model.py
@@ -0,0 +1,812 @@
+# -*- coding: utf-8 -*-
+
+from trac.evaluation.api import EvaluationModel, ModelVariable, ModelConstant, \
+ SubjectArea, ClusterArea, \
+ UnityScale, RatioScale, PercentScale, BooleanScale, NominalScale, OrdinalScale, \
+ EvalVariableError, \
+ varlib, UserRole, get_enum_equivalents, revert_enum
+from trac.evaluation.sources import tktsrc as ts
+
+class Model(EvaluationModel):
+
+ ENUM_MAP = {
+ 'priority': {
+ u'второстепенная': 1,
+ u'минорная': 2,
+ u'обычная': 3,
+ u'важная': 4,
+ u'критическая': 5,
+ '*': 1,
+ },
+ 'resolution': {
+ 'done': 1,
+ 'invalid': 0,
+ 'outdated': 0,
+ 'incomplete': 1,
+ 'reassigned': 1,
+ '*': 1,
+ },
+ 'severity': {
+ u'простейшая': 1,
+ u'простая': 2,
+ u'обычная': 3,
+ u'сложнее среднего': 4,
+ u'трудная': 5,
+ '*': 1,
+ },
+ 'type': {
+ u'программирование': 1,
+ u'проектирование': 1,
+ u'документирование': 1,
+ u'исправление ошибки': 1,
+ u'подготовка данных': 1,
+ u'тестирование': 1,
+ u'точка планирования': 0,
+ u'оценивание': 0,
+ '*': 1,
+ },
+ }
+
+ TICKET_VALUE_HELP = u'''
+Стоимость задачи рассчитывается на основе значений следующих свойств:
+
+ * приоритет;
+ * серьезность;
+ * модификатор стоимости;
+ * тип задачи;
+
+Формула для расчета: **тип** * (**приоритет** * **серьезность** + **модификатор стоимости**).
+
+Значение стоимости округляется до целого и не может быть отрицательным.
+
+Подходите с ответственностью к выставлению значений для указанных свойств задач.
+
+Если задаче выставлен высокий **приоритет** (повышающий её стоимость),
+то и выполнена задача должна быть в назначенный крайний срок. В противном случае
+если задача была выполнена с большим запозданием, её приоритет по факту снизился
+и должен быть **изменен перед закрытием задачи**.
+
+Если свойства задачи по её завершении соответствуют действительности, но
+исполнитель выполнил её очень //оперативно// или сделал что-то //сверх поставленной задачи//,
+это необходимо отразить с помощью **модификатора стоимости** — выставить бонус.
+'''
+ TICKET_VALUE_ENUM_LIST = ('type', 'priority', 'severity')
+
+ VAR_PROJECT_RATING = 'project_rating'
+ VAR_INDIVIDUAL_RATING = 'individual_rating'
+ VAR_FINAL_RATING = 'final_rating'
+
+ VARS_MILESTONE_RATING = ('milestone_expert', 'valid_tickets', 'completed_tickets', 'earned_by_tickets_target',
+ 'completion', 'completion_by_val', 'avg_severity')
+
+ VARS_MILESTONE_TEAM_EVAL_MANAGER = ('milestone_peer_grade', 'individual_earned_rating',
+ 'earned_by_tickets', 'completed_tickets', 'created_tickets', 'avg_severity')
+ VARS_MILESTONE_TEAM_EVAL_DEVELOPER = ('milestone_peer_grade_afterall', 'individual_earned_rating',
+ 'earned_by_tickets', 'completed_tickets', 'created_tickets', 'avg_severity')
+
+ VARS_PROJECT_RATING = ('project_rating', 'completion', 'completion_by_val',
+ 'milestones_total', 'project_expert', 'earned_by_tickets_target', 'avg_severity')
+ VARS_INDIVIDUAL_RATING = ('final_rating', 'individual_rating', 'individual_earned_rating',
+ 'peer_individual_rating', 'completed_tickets', 'created_tickets', 'avg_severity')
+
+ PROJECT_EVAL_CRITERIA = {
+ 'completion': {
+ 'order': 1,
+ 'label': u'Готовность проекта',
+ 'description': u'Завершенность разработки программы, являвшейся целью проекта.',
+ 'scale': PercentScale(),
+ },
+ 'swing_practice': {
+ 'order': 2,
+ 'label': u'Успех освоения Java Swing',
+ 'description': u'Насколько хорошо освоен Swing, если судить по функциональности и интерфейсам разработанной программы.',
+ 'scale': PercentScale(),
+ },
+ 'good_teamwork': {
+ 'order': 3,
+ 'label': u'Успешно работали в команде [Бонус]',
+ 'description': u'Слаженно ли проходила коллективная работа, получены ли навыки командой работы.',
+ 'scale': BooleanScale(),
+ },
+ 'test_crit1': {
+ 'order': 4,
+ 'label': u'Наибольший успех достигнут в',
+ 'description': u'Тестовый критерий с номинальной шкалой. Не используется при формировании оценки.',
+ 'scale': NominalScale([u'проектирование интерфейсов', u'разработка алгоритмов']),
+ },
+ 'test_crit2': {
+ 'order': 5,
+ 'label': u'Выполнение работ, сдача этапов и т.д. в срок',
+ 'description': u'Тестовый критерий с порядковой шкалой. Не используется при формировании оценки.',
+ 'scale': OrdinalScale({u'всегда': 5, u'почти всегда': 4, u'обычно': 3, u'редко': 2, u'никогда': 1}),
+ },
+ }
+
+
+ def get_ticket_value(self, ticket):
+ tkt = ticket
+ p = self.get_enum_value('priority', tkt['priority'])
+ s = self.get_enum_value('severity', tkt['severity'])
+ t = self.get_enum_value('type', tkt['type'])
+ m = int(tkt['modifier'] or 0)
+ base_value = int(round(max(0, t * (p * s + m) )))
+ return base_value
+
+
+
+class CompletedTicketsVar(varlib.CountTickets):
+
+ model_cls = Model
+
+ subject_support = (SubjectArea.USER, SubjectArea.PROJECT)
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ # varlib.CountTickets specific vars
+ filter_tickets = (
+ (ts.Status()=='closed') &
+ (ts.Resolution()=='done')
+ )
+
+ alias = 'completed_tickets'
+ label = u'Количество выполненных задач'
+ description = u'''
+Количество выполненных задач (закрытые как done карточки).
+'''
+
+class CreatedTicketsVar(varlib.CountTickets):
+
+ model_cls = Model
+
+ subject_support = (SubjectArea.USER, SubjectArea.PROJECT)
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ # varlib.CountTickets specific vars
+ filter_tickets = ~ (
+ (ts.Status()=='closed') &
+ (ts.Resolution()!='done')
+ )
+ limit_project_users_field = ts.Reporter()
+ limit_allow_empty = False
+ user_field = ts.Reporter()
+
+ alias = 'created_tickets'
+ label = u'Количество созданных задач'
+ description = u'''
+Количество созданных членами команды валидных задач
+(исключены закрытые как невалидные или неактуальные).
+'''
+
+class ValidTicketsVar(varlib.CountTickets):
+
+ model_cls = Model
+
+ subject_support = (SubjectArea.USER, SubjectArea.PROJECT)
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ # varlib.CountTickets specific vars
+ filter_tickets = ~ (
+ (ts.Status()=='closed') &
+ (ts.Resolution()!='done')
+ )
+ limit_allow_empty = True
+
+ alias = 'valid_tickets'
+ label = u'Количество всех валидных задач'
+ description = u'''
+Количество всех валидных задач (исключены закрытые как невалидные или неактуальные).
+Подсчитываются только те задачи, у которых либо еще нет исполнителя, либо исполнителем
+является член команды.
+'''
+
+class CompletionVar(varlib.TwoVarsRatio):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.PROJECT
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ # varlib.TwoVarsRatio specific vars
+ var1 = 'completed_tickets'
+ var2 = 'valid_tickets'
+
+ alias = 'completion'
+ label = u'Завершенность по задачам'
+ description = u'''
+Отношение количества выполненных задач к числу всех валидных задач.
+'''
+
+
+class CompletionByValuesVar(varlib.TwoVarsRatio):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.PROJECT
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ # varlib.TwoVarsRatio specific vars
+ var1 = 'earned_by_tickets'
+ var2 = 'ticket_values_sum'
+
+ alias = 'completion_by_val'
+ label = u'Завершенность по задачам (с учетом стоимостей)'
+ description = u'''
+Отношение суммы стоимостей выполненных задач к сумме стоимостей всех валидных задач.
+'''
+
+
+class EarnedByTicketsVar(ModelVariable):
+
+ model_cls = Model
+
+ scale = RatioScale(int)
+
+ subject_support = (SubjectArea.USER, SubjectArea.PROJECT)
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ alias = 'earned_by_tickets'
+ label = u'Заработано по стоимости задач'
+ description = u'''
+Баллы, заработанные за выполненные задачи. Рассчитывается
+суммированием стоимостей задач.
+'''
+
+ def _get(self):
+ q = self.model.sources['ticket']
+ self > q
+ q.where(
+ (ts.Status()=='closed') &
+ (ts.Resolution()=='done')
+ )
+ if self['area'] == SubjectArea.PROJECT:
+ q.limit_to_project_users(ts.Owner())
+ res = q.sum(ts.TicketValue())
+ return res
+
+
+class ValidTicketValuesSum(ModelVariable):
+
+ model_cls = Model
+
+ scale = RatioScale(int)
+
+ subject_support = SubjectArea.PROJECT
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ alias = 'ticket_values_sum'
+ label = u'Суммарная стоимость задач'
+ description = u'''
+Сумма стоимостей всех валидных задач (завершенных и незавершенных).
+'''
+
+ def _get(self):
+ q = self.model.sources['ticket']
+ self > q
+ q.where(~(
+ (ts.Status()=='closed') &
+ (ts.Resolution()!='done')
+ )
+ )
+ q.limit_to_project_users(ts.Owner())
+ res = q.sum(ts.TicketValue())
+ return res
+
+
+class EarnedByTicketsSumTarget(ModelVariable):
+
+ model_cls = Model
+
+ scale = RatioScale(float)
+
+ subject_support = SubjectArea.PROJECT
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ alias = 'earned_by_tickets_target'
+ label = u'Целевая сумма баллов за задачи'
+ description = u'''
+Сумма стоимостей всех валидных задач (завершенных и незавершенных),
+приходящаяся в среднем на каждого члена команды.
+'''
+
+ def _get(self):
+ esum = self.model.vars['ticket_values_sum']
+ self > esum
+ total = esum.get()
+ uinfo = self.model.sources['user_info']
+ self > uinfo
+ size = uinfo.role(UserRole.DEVELOPER).count()
+ return float(total) / size
+
+
+class TeamMilestoneGrade(varlib.TeamMilestoneVariable):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.USER
+ cluster_support = ClusterArea.MILESTONE
+
+ # varlib.TeamMilestoneVariable specific vars
+ with_authors = False
+ all_completed = False
+ only_approved = True
+
+ alias = 'milestone_peer_grade'
+ label = u'Оценка по взаимному оцениванию за этап'
+ description = u'''
+Значение, полученное суммированием и усреднением результатов взаимного оценивания.
+'''
+
+ def process_results(self, results, msum, team_size):
+ cnt = len(results)
+ if not cnt:
+ raise EvalVariableError(u'Данные по взаимному оцениванию отсутствуют')
+ value = ( sum(results) / float(cnt * msum) ) * team_size
+ return value
+
+class TeamMilestoneGradeAfterAll(TeamMilestoneGrade):
+
+ model_cls = Model
+
+ all_completed = True
+
+ alias = 'milestone_peer_grade_afterall'
+ label = u'Оценка по взаимному оцениванию (пройдено всеми) за этап'
+ description = u'''
+Значение, полученное суммированием и усреднением результатов взаимного оценивания.
+Значение может быть получено только после того, как формы взаимного оценивания
+заполнят все члены команды.
+'''
+
+
+
+class ExpertProjectGrade(varlib.ProjectCriteria):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ # varlib.ProjectCriteria specific vars
+ all_completed = True
+
+ alias = 'project_expert'
+ label = u'Экспертная оценка проекта'
+ description = u'''
+Оценка, сформированная по данным электронного анкетирования
+для оценивания результатов выполнения проекта.
+'''
+
+ def process_results(self, criteria, values):
+ compl_weight = self.model.constants['exp_project_completion']
+ learn_weight = self.model.constants['exp_learning_objectives']
+ bonus = values['good_teamwork'] and 0.05 or 0
+ value = compl_weight * values['completion'] / 100 + \
+ learn_weight * values['swing_practice'] / 100 + \
+ bonus
+ return value
+
+
+class MilestoneExpertRating(ModelVariable):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.PROJECT
+ cluster_support = ClusterArea.MILESTONE
+
+ alias = 'milestone_expert'
+ label = u'Экспертная оценка за этап'
+ description = u'''
+Рейтинг, выставленный менеджером за этап.
+'''
+
+ def _get(self):
+ q = self.model.sources['milestone']
+ self > q
+ q.include(rating=True)
+ r = q.get()
+ return float(r) / 100
+
+
+class MilestonesResultsVar(varlib.ProjectMilestones):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ # varlib.ProjectMilestones specific vars
+ only_approved = True
+ only_completed = False
+
+ alias = 'milestones_total'
+ label = u'Оценка за все этапы'
+ description = u'''
+Оценка, сформированная по рейтингам и весам, выставленным для этапов проекта.
+'''
+
+ def process_milestones(self, milestones, total_weight):
+ approved_cnt = len(milestones)
+ if not approved_cnt:
+ raise EvalVariableError(u'В проекте нет ни одного утвержденного этапа')
+# completed_list = [data for data in milestones.values() if data['completed']]
+ mlist = milestones.values() # незавершенным можно просто не ставить рейтинг
+ # или выставлять промежуточный
+ if not total_weight:
+ sum_func = lambda s, m: s+m['rating']
+ norm = 100.0 * approved_cnt
+ else:
+ sum_func = lambda s, m: s + m['weight']*m['rating']
+ norm = 100.0 * total_weight
+ total_rating = reduce(sum_func, mlist, 0)
+ return total_rating / norm
+
+
+class ProjectRating(varlib.MultiVars):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.PROJECT
+
+ # varlib.MultiVars specific vars
+ var_list = ('completion_by_val', 'milestones_total', 'project_expert')
+
+ alias = 'project_rating'
+ label = u'Итоговая оценка за проект'
+ description = u'''
+Итоговая оценка за проект, сформированная суммированием с весами
+1) степени завершенности проекта по задачам (с учетом их стоимостей);
+2) оценки за все этапы проекта;
+3) экспертной оценки проекта.
+'''
+
+ def process_variables(self, completion, ms_total, expert):
+ self > completion
+ self > ms_total
+ self > expert
+ completion_weight = self.model.constants['project_completion']
+ milestones_weight = self.model.constants['project_milestones']
+ expert_weight = self.model.constants['project_expert']
+ completion = completion.get()
+ ms_total = ms_total.get()
+ expert = expert.get()
+ value = completion_weight * completion + \
+ milestones_weight * ms_total + \
+ expert_weight * expert
+ return value
+
+
+
+class IndividualEarnedRatio(varlib.MultiVars):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.USER
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ # varlib.MultiVars specific vars
+ var_list = ('earned_by_tickets', 'earned_by_tickets_target')
+
+ alias = 'individual_earned_rating'
+ label = u'Индивидуальный вклад по задачам'
+ description = u'''
+Индивидуальная оценка, рассчитанная как отношение баллов за выполненные
+задачи к целевой сумме баллов по задачам (сумме стоимостей всех валидных
+задач (завершенных и незавершенных), приходящаяся в среднем на каждого
+члена команды).
+'''
+
+ def process_variables(self, earned, target):
+ self > earned
+ self > target
+ target.project(self['project_id']) # вернуть область запроса "проект"
+ u = earned.get()
+ t = target.get()
+ if not t:
+ return 0
+ value = float(u) / t
+ return value
+
+
+
+class PeerIndividualRating(varlib.ProjectMilestones):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.USER
+
+ # varlib.ProjectMilestones specific vars
+ only_approved = True
+ only_completed = False
+
+ alias = 'peer_individual_rating'
+ label = u'Индивидуальная оценка по взаимному оцениванию'
+ description = u'''
+Индивидуальная оценка, рассчитанная суммированием результатов
+взаимного оценивания за утвержденные этапы проекта с учетом весов этапов.
+'''
+
+ def process_milestones(self, milestones, total_weight):
+ peergrade = self.model.vars['milestone_peer_grade']
+
+ # суммирование с учетом весов этапов (если веса используются)
+ self > peergrade
+ approved_cnt = len(milestones)
+ if not approved_cnt:
+ raise EvalVariableError(u'В проекте нет ни одного утвержденного этапа')
+
+ mlist = milestones.values()
+ if not total_weight:
+ sum_func = lambda s, m: s + peergrade.milestone(m['name']).get()
+ norm = approved_cnt
+ else:
+ sum_func = lambda s, m: s + m['weight'] * peergrade.milestone(m['name']).get()
+ norm = total_weight
+ total_rating = reduce(sum_func, mlist, 0)
+ peertotal = total_rating / norm
+
+ return peertotal
+
+
+class IndividualRating(varlib.MultiVars):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.USER
+
+ # varlib.MultiVars specific vars
+ var_list = ('individual_earned_rating', 'peer_individual_rating')
+
+ alias = 'individual_rating'
+ label = u'Индивидуальная оценка за проект'
+ description = u'''
+Индивидуальная оценка, рассчитанная суммированием индивидуального вклада
+по задачам всего проекта и результатов взаимного оценивания за утвержденные
+этапы проекта с учетом весов этапов.
+'''
+
+ def process_variables(self, earned, peer):
+ earned_weight = self.model.constants['indiv_earned_weight']
+ peer_weight = self.model.constants['indiv_peer_weight']
+ self > earned
+ self > peer
+ earned = earned.get()
+ peer = peer.get()
+
+ value = earned_weight * earned + peer_weight * peer
+ return value
+
+
+class FinalRating(varlib.MultiVars):
+
+ model_cls = Model
+
+ scale = UnityScale()
+
+ subject_support = SubjectArea.USER
+
+ # varlib.MultiVars specific vars
+ var_list = ('project_rating', 'individual_rating')
+
+ alias = 'final_rating'
+ label = u'Итоговая индивидуальная оценка'
+ description = u'''
+Итоговая индивидуальная оценка за проект, сформированная суммированием
+с весами итоговой оценки за проект и индивидуальной оценки.
+'''
+ def process_variables(self, project, individual):
+ self > individual
+ project.project(self['project_id'])
+ project_weight = self.model.constants['final_project_weight']
+ individual_weight = self.model.constants['final_individual_weight']
+ project = project.get()
+ individual = individual.get()
+ value = project_weight * project + \
+ individual_weight * individual
+ return value
+
+
+
+# Extras #
+
+class AvgSeverityVar(ModelVariable):
+
+ model_cls = Model
+
+ subject_support = (SubjectArea.USER, SubjectArea.PROJECT)
+ cluster_support = (ClusterArea.NONE, ClusterArea.MILESTONE)
+
+ alias = 'avg_severity'
+ label = u'Средняя сложность выполненных задач'
+ description = u'''
+Средняя сложность выполненных задач, рассчитываемая с учетом
+числовых эквивалентов для соответствующих значений сложности.
+'''
+
+ def _get(self):
+ q = self.model.sources['ticket']
+ self > q
+ q.where(
+ (ts.Status()=='closed') &
+ (ts.Resolution()=='done')
+ )
+ if self['area'] == SubjectArea.PROJECT:
+ q.limit_to_project_users(ts.Owner())
+ q.only(ts.Severity)
+ row = q.get()
+ if not row:
+ raise EvalVariableError(u'Нет выполненных задач')
+
+ nums = get_enum_equivalents(self.model, 'severity', row)
+ num = sum(nums) / float(len(nums))
+ res = revert_enum(self.model, 'severity', num)
+ return res
+
+
+
+
+
+###################
+# Model constants #
+###################
+
+class ExpertProjectCompletionWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.7
+
+ alias = 'exp_project_completion'
+ label = u'[Эксперт] Вес оценки завершенности проекта'
+ description = u'''
+Вес оценки завершенности проекта для расчета экспертной оценки проекта.
+'''
+
+class ExpertLearningCompletionWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.3
+
+ alias = 'exp_learning_objectives'
+ label = u'[Эксперт] Суммарный вес целей обучения'
+ description = u'''
+Суммарный вес целей обучения для расчета экспертной оценки проекта.
+'''
+
+
+class ProjectCompletionWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.1
+
+ alias = 'project_completion'
+ label = u'[Итоговая за проект] Вес оценки завершенности проекта'
+ description = u'''
+Вес оценки завершенности проекта для расчета итоговой оценки за проект.
+'''
+
+
+class ProjectMilestonesWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.4
+
+ alias = 'project_milestones'
+ label = u'[Итоговая за проект] Вес суммарной оценки за этапы'
+ description = u'''
+Вес суммарной оценки за этапы проекта для расчета итоговой оценки за проект.
+'''
+
+
+class ProjectExpertWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.5
+
+ alias = 'project_expert'
+ label = u'[Итоговая за проект] Вес экспертной оценки проекта'
+ description = u'''
+Вес экспертной оценки проекта для расчета итоговой оценки за проект.
+'''
+
+
+
+class IndividualEarnedWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.5
+
+ alias = 'indiv_earned_weight'
+ label = u'[Индивидуальная за проект] Вес индивидуального вклада'
+ description = u'''
+Вес оценки индивидуального вклада для расчета индивидуальной
+оценки за проект.
+'''
+
+
+
+class IndividualPeerWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.5
+
+ alias = 'indiv_peer_weight'
+ label = u'[Индивидуальная за проект] Вес оценки по взаимному оцениванию'
+ description = u'''
+Вес оценки по взаимному оцениванию для расчета индивидуальной
+оценки за проект.
+'''
+
+
+
+class FinalProjectWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.5
+
+ alias = 'final_project_weight'
+ label = u'[Итоговая индивидуальная] Вес оценки за проект'
+ description = u'''
+Вес оценки за проект для расчета итоговой индивидуальной
+оценки за проект.
+'''
+
+
+
+class FinalIndividualWeight(ModelConstant):
+
+ model_cls = Model
+
+ scale = UnityScale()
+ default_value = 0.5
+
+ alias = 'final_individual_weight'
+ label = u'[Итоговая индивидуальная] Вес индивидуальной оценки за проект'
+ description = u'''
+Вес индивидуальной оценки за проект для расчета итоговой индивидуальной
+оценки за проект.
+'''
+
+
+class TestBoolConstant(ModelConstant):
+
+ model_cls = Model
+
+ scale = BooleanScale()
+ default_value = True
+
+ alias = 'test_bool_constant'
+ label = u'Тестовая константа Да/Нет'
+ description = u'''
+Тестовая константа со шкалой BooleanScale
+'''
+
+
+
View
BIN  downloads/simple_model.tar.gz
Binary file not shown
View
BIN  downloads/trac-svn-hooks.tar.gz
Binary file not shown
View
428 downloads/trac.ini
@@ -0,0 +1,428 @@
+# -*- coding: utf-8 -*-
+
+[account-manager]
+allow_delete_account = false
+force_passwd_change = true
+generated_password_length = 8
+hash_method = HtDigestHashMethod
+login_attempt_max_count = 3
+login_opt_list = false
+password_store = AccountManagerIntegration
+persistent_sessions = true
+refresh_passwd = false
+reset_password = true
+user_lock_time = 15
+user_lock_time_progression = 2
+verify_email = false
+
+[attachment]
+max_size = 262144
+render_unsafe_content = false
+
+[authz_policy]
+authz_file =
+
+[browser]
+color_scale = True
+downloadable_paths = /trunk, /branches/*, /tags/*
+hide_properties = svk:merge
+intermediate_color =
+intermediate_point =
+newest_color = (255, 136, 136)
+oldest_color = (136, 136, 255)
+oneliner_properties = trac:summary
+render_unsafe_content = false
+wiki_properties = trac:description
+
+[changeset]
+max_diff_bytes = 10000000
+max_diff_files = 0
+wiki_format_messages = true
+
+[components]
+acct_mgr.admin.accountmanageradminpages = enabled
+acct_mgr.api.accountmanager = enabled
+acct_mgr.guard.accountguard = enabled
+acct_mgr.pwhash.htdigesthashmethod = enabled
+acct_mgr.web_ui.* = enabled
+ganttcalendar.api.tracganttcalendar = enabled
+ganttcalendar.complete_by_close.ganttcompleteticketobserver = enabled
+ganttcalendar.ticketcalendar.ticketcalendar = enabled
+ganttcalendar.ticketgantt.ticketganttchart = enabled
+ganttcalendar.ticketvalidator.ganttticketvalidator = enabled
+inieditorpanel.default_manager.inieditoremptysecuritymanager = enabled
+inieditorpanel.web_ui.traciniadminpanel = enabled
+mastertickets.* = enabled
+svnadmin.acct_mgr_listener.accountmanagertosvnreplication = enabled
+svnadmin.admin.svnadminpanel = enabled
+svnadmin.api.svnadmin = enabled
+svnadmin.api.svnrepositoryprovider = enabled
+teamcalendar.* = enabled
+timingandestimationplugin.api.timetrackingsetupparticipant = enabled
+timingandestimationplugin.ticket_daemon.timetrackingticketobserver = enabled
+timingandestimationplugin.ticket_daemon.timetrackingticketvalidator = enabled
+timingandestimationplugin.webui.hourslayoutchanger = enabled
+timingandestimationplugin.webui.querywebuiaddon = enabled
+timingandestimationplugin.webui.ticketwebuiaddon = enabled
+timingandestimationplugin.webui.timingestimationwebui = enabled
+trac.notification.notificationsystem = enabled
+trac.notification.sendmailemailsender = disabled
+trac.notification.smtpemailsender = enabled
+trac.search.web_ui.searchmodule = disabled
+trac.web.auth.loginmodule = disabled
+tracdeveloper.apidoc.apidocumentation = enabled
+tracdeveloper.debugger.templatedebugger = enabled
+tracdeveloper.dozer.dozer = enabled
+tracdeveloper.javascript.javascriptdevelopermodule = enabled
+tracdeveloper.log.developerlogmodule = disabled
+tracdeveloper.main.developerplugin = enabled
+tracdeveloper.plugins.pluginregistry = enabled
+tracmenus.web_ui.menumanagermodule = enabled
+tracmetrix.* = enabled
+tracmetrix.web_ui.milestonemetrixintegrator = disabled
+tracmetrix.web_ui.roadmapmetrixintegrator = disabled
+tracopt.perm.authz_policy.authzpolicy = disabled
+tracopt.perm.config_perm_provider.extrapermissionsprovider = enabled
+tracopt.ticket.commit_updater.* = enabled
+tracopt.ticket.deleter.ticketdeleter = enabled
+translatedpages.translatedpages.translatedpagesmacro = enabled
+worklog.api.worklogsetupparticipant = enabled
+worklog.ticket_daemon.worklogticketobserver = enabled
+worklog.ticket_filter.worklogticketaddon = enabled
+worklog.timeline_hook.worklogtimelineaddon = enabled
+worklog.webadminui.worklogadminpanel = enabled
+worklog.webui.worklogpage = enabled
+
+[extra-permissions]
+extra_ticket_perms = TICKET_ASSIGN, TICKET_SELF_ASSIGN, TICKET_APPROVE, TICKET_MODIFY_CLOSED, TICKET_CLOSE_NEW, TICKET_PEER_REVIEW, TICKET_TEAM_CHECK, TICKET_MAN_CHECK, TICKET_MANDATORY_ASSIGN, TICKET_REOPEN
+
+[ganttcalendar]
+default_zoom_mode = 2
+first_day = 1
+
+[header_logo]
+alt = EduTrac
+height = -1
+link = /
+src =
+width = -1
+
+[inherit]
+plugins_dir =
+templates_dir =
+
+[logging]
+log_level = DEBUG
+log_type = stderr
+
+[mainnav]
+browser = enabled
+browser.hide_if_no_original = true
+browser.label = Браузер
+browser.order = 1
+browser.parent = browsergrp
+browser_timeline = enabled
+browser_timeline.href = /timeline?changeset=on
+browser_timeline.label = Последние изменения
+browser_timeline.order = 2
+browser_timeline.parent = browsergrp
+browser_timeline.perm = BROWSER_VIEW
+browsergrp = enabled
+browsergrp.hide_if_no_children = true
+browsergrp.href = /browser
+browsergrp.label = Репозитории
+browsergrp.order = 40
+debug_eval_var = enabled
+debug_eval_var.hide_if_no_original = true
+debug_eval_var.label = Отладка переменных оценивания
+debug_eval_var.order = 10
+debug_eval_var.parent = evalgrp
+depgraph = enabled
+depgraph.hide_if_no_original = true
+depgraph.label = Граф зависимостей задач
+depgraph.order = 1
+depgraph.parent = plangrp
+evalgrp = enabled
+evalgrp.hide_if_no_children = true
+evalgrp.href = #
+evalgrp.label = Оценивание
+evalgrp.order = 70
+groupctrlgrp = enabled
+groupctrlgrp.hide_if_no_children = true
+groupctrlgrp.href = #
+groupctrlgrp.label = Контроль группы
+groupctrlgrp.order = 60
+gwiki = enabled
+gwiki.href = /wiki/WikiTOC
+gwiki.label = Глобальные Wiki
+gwiki.order = 2
+gwiki.parent = wikigrp
+home = enabled
+home.href = /
+home.label = Главная
+home.order = 10
+individual_eval = enabled
+individual_eval.hide_if_no_original = true
+individual_eval.label = Индивидуальное оценивание
+individual_eval.order = 3
+individual_eval.parent = evalgrp
+lastticketevnts = enabled
+lastticketevnts.href = /timeline?ticket=on&ticket_details=on
+lastticketevnts.label = Последние изменения (список событий)
+lastticketevnts.order = 3
+lastticketevnts.parent = ticketgrp
+lastticketevnts.perm = TICKET_VIEW
+lasttickets = enabled
+lasttickets.href = /report/6
+lasttickets.label = Последние изменения (список задач)
+lasttickets.order = 2
+lasttickets.parent = ticketgrp
+lasttickets.perm = TICKET_VIEW
+mdashboard = enabled
+mdashboard.hide_if_no_original = true
+mdashboard.label = Метрики этапа
+mdashboard.order = 2
+mdashboard.parent = statsgrp
+milestones_eval = enabled
+milestones_eval.hide_if_no_original = true
+milestones_eval.label = Оценивание этапов
+milestones_eval.order = 2
+milestones_eval.parent = evalgrp
+newticket = enabled
+newticket.hide_if_no_original = true
+newticket.label = Новая карточка
+newticket.order = 1
+newticket.parent = ticketgrp
+pdashboard = enabled
+pdashboard.hide_if_no_original = true
+pdashboard.label = Метрики проекта
+pdashboard.order = 1
+pdashboard.parent = statsgrp
+plangrp = enabled
+plangrp.hide_if_no_children = true
+plangrp.href = /roadmap
+plangrp.label = Планирование
+plangrp.order = 50
+project_eval = enabled
+project_eval.hide_if_no_original = true
+project_eval.label = Оценивание проекта
+project_eval.order = 1
+project_eval.parent = evalgrp
+pwiki = enabled
+pwiki.href = /wiki/WikiTOCP
+pwiki.label = Wiki проекта
+pwiki.order = 1
+pwiki.parent = wikigrp
+pwiki.perm = TICKET_VIEW
+query = enabled
+query.href = /query
+query.label = Произвольный запрос
+query.order = 5
+query.parent = ticketgrp
+query.perm = TICKET_VIEW
+querygrparea = enabled
+querygrparea.href = /query?area=group&status=!closed
+querygrparea.label = Задачи
+querygrparea.order = 1
+querygrparea.parent = groupctrlgrp
+querygrparea.perm = TICKET_VIEW_GROUP_AREA
+roadmap = enabled
+roadmap.hide_if_no_original = true
+roadmap.label = Этапы проекта
+roadmap.order = 1
+roadmap.parent = plangrp
+statsgrp = enabled
+statsgrp.hide_if_no_children = true
+statsgrp.href = #
+statsgrp.label = Статистика
+statsgrp.order = 80
+teamcalendar = enabled
+teamcalendar.hide_if_no_original = true
+teamcalendar.label = Календарь команды
+teamcalendar.order = 5
+teamcalendar.parent = plangrp
+ticketcalendar = enabled
+ticketcalendar.hide_if_no_original = true
+ticketcalendar.label = Календарь задач
+ticketcalendar.order = 3
+ticketcalendar.parent = plangrp
+ticketgantt = enabled
+ticketgantt.hide_if_no_original = true
+ticketgantt.label = Диаграмма Ганта
+ticketgantt.order = 4
+ticketgantt.parent = plangrp
+ticketgrp = enabled
+ticketgrp.hide_if_no_children = true
+ticketgrp.href = /report
+ticketgrp.label = Задачи
+ticketgrp.order = 30
+tickets = enabled
+tickets.hide_if_no_original = true
+tickets.label = Просмотр карточек
+tickets.order = 4
+tickets.parent = ticketgrp
+timeline = enabled
+timeline.hide_if_no_original = true
+timeline.label = История изменений
+timeline.order = 35
+timelinegrparea = enabled
+timelinegrparea.href = /timeline?area=group
+timelinegrparea.label = Хронология
+timelinegrparea.order = 2
+timelinegrparea.parent = groupctrlgrp
+timelinegrparea.perm = TIMELINE_VIEW_GROUP_AREA
+udashboard = enabled
+udashboard.hide_if_no_original = true
+udashboard.label = Метрики пользователя
+udashboard.order = 3
+udashboard.parent = statsgrp
+wiki = disabled
+wiki.label = Wiki
+wiki.order = 20
+wikigrp = enabled
+wikigrp.hide_if_no_children = true
+wikigrp.href = #
+wikigrp.label = Wiki
+wikigrp.order = 20
+worklog = enabled
+worklog.hide_if_no_original = true
+worklog.label = Отчеты по работе
+worklog.order = 70
+
+[menu-custom]
+managed_menus = mainnav
+
+[milestone]
+stats_provider = DefaultTicketGroupStatsProvider
+
+[mimeviewer]
+max_preview_size = 262144
+mime_map = text/x-dylan:dylan,text/x-idl:ice,text/x-ada:ads:adb
+pygments_default_style = trac
+pygments_modes =
+tab_width = 8
+treat_as_binary = application/octet-stream,application/pdf,application/postscript,application/msword,application/rtf,
+
+[notification]
+admit_domains =
+always_notify_owner = true
+always_notify_reporter = false
+always_notify_updater = false
+ambiguous_char_width = single
+email_sender = SmtpEmailSender
+ignore_domains =
+mime_encoding = base64
+notify_own_changes = false
+notify_untranslated = false
+sendmail_path = sendmail
+smtp_always_bcc =
+smtp_always_cc =
+smtp_default_domain =
+smtp_enabled = true
+smtp_from = ###################
+smtp_from_name = EduTrac Notification
+smtp_password = ###################
+smtp_port = 587
+smtp_replyto = ###################
+smtp_server = ###################
+smtp_subject_prefix = [EduTrac]
+smtp_user = edutrac.noreply
+ticket_subject_template = $prefix #$ticket.id: $summary
+use_public_cc = false
+use_short_addr = false
+use_tls = true
+
+[project]
+admin = ###################
+admin_trac_url =
+descr = EduTrac Environment
+footer = ###################
+icon = common/trac.ico
+name = EduTrac
+url = /
+
+[query]
+default_anonymous_query = status!=closed&cc~=$USER
+default_query = status!=closed&owner=$USER
+items_per_page = 100
+ticketlink_query = ?status=!closed
+
+[report]
+items_per_page = 100
+items_per_page_rss = 0
+
+[revisionlog]
+default_log_limit = 100
+
+[roadmap]
+stats_provider = DefaultTicketGroupStatsProvider
+
+[search]
+min_query_length = 3
+
+[svn]
+branches = trunk,branches/*
+tags = tags/*
+
+[svnadmin]
+chmod = -R g+rws
+hooks_path = /home/trac/env/main/svn
+parent_path = /home/svn
+passwd_path = /etc/subversion/passwd
+repos_url_prefix = http://###################
+
+[ticket]
+default_resolution =
+max_comment_size = 262144
+max_description_size = 262144
+restrict_owner = true
+workflow = ConfigurableTicketWorkflow
+
+[timeline]
+abbreviated_messages = True
+changeset_collapse_events = false
+changeset_long_messages = false
+changeset_show_files = 0
+default_daysback = 10
+max_daysback = 270
+newticket_formatter = oneliner
+ticket_show_details = true
+
+[trac]
+authz_file = /etc/subversion/authz.conf
+auto_preview_timeout = 2.0
+auto_reload = false
+base_url = http://###################
+database = postgres://###################:###################@###################/trac
+debug_sql = false
+default_charset = utf-8
+default_timezone = Europe/Moscow
+genshi_cache_size = 128
+ignore_auth_case = true
+repository_sync_per_request =
+secure_cookies = false
+show_email_addresses = true
+use_base_url_for_redirect = false
+
+[translatedpages]
+template = Translation{lang}/{page}
+
+[versioncontrol]
+allowed_repository_dir_prefixes =
+
+[wiki]
+ignore_missing_pages = false
+max_size = 262144
+render_unsafe_content = false
+safe_schemes = cvs,file,ftp,git,irc,http,https,news,sftp,smb,ssh,svn,svn+ssh
+split_page_names = false
+
+[worklog]
+autoreassignaccept = False
+autostop = False
+autostopstart = True
+comment = True
+roundup = 1
+timingandestimation = True
+trachoursplugin = False
+
View
32 downloads/trac.wsgi
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C)2008-2009 Edgewall Software
+# Copyright (C) 2008 Noah Kantrowitz <noah@coderanger.net>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+#
+# Author: Noah Kantrowitz <noah@coderanger.net>
+import os
+
+def application(environ, start_request):
+ if not 'trac.env_parent_dir' in environ:
+ environ.setdefault('trac.env_path', '/home/trac/env/main')
+ if 'PYTHON_EGG_CACHE' in environ:
+ os.environ['PYTHON_EGG_CACHE'] = environ['PYTHON_EGG_CACHE']
+ elif 'trac.env_path' in environ:
+ os.environ['PYTHON_EGG_CACHE'] = \
+ os.path.join(environ['trac.env_path'], '.egg-cache')
+ elif 'trac.env_parent_dir' in environ:
+ os.environ['PYTHON_EGG_CACHE'] = \
+ os.path.join(environ['trac.env_parent_dir'], '.egg-cache')
+ environ['trac.locale'] = 'ru_RU.utf8'
+ from trac.web.main import dispatch_request
+ return dispatch_request(environ, start_request)
Please sign in to comment.
Something went wrong with that request. Please try again.