917 lines
35 KiB
Python
917 lines
35 KiB
Python
# -*- coding: iso-8859-15 -*-
|
|
|
|
|
|
# Glasnost
|
|
# By: Odile Bénassy <obenassy@entrouvert.com>
|
|
# Romain Chantereau <rchantereau@entrouvert.com>
|
|
# Nicolas Clapiès <nclapies@easter-eggs.org>
|
|
# Pierre-Antoine Dejace <padejace@entrouvert.be>
|
|
# Thierry Dulieu <tdulieu@easter-eggs.com>
|
|
# Florent Monnier <monnier@codelutin.com>
|
|
# Cédric Musso <cmusso@easter-eggs.org>
|
|
# Frédéric Péters <fpeters@entrouvert.be>
|
|
# Benjamin Poussin <poussin@codelutin.com>
|
|
# Emmanuel Raviart <eraviart@entrouvert.com>
|
|
# Sébastien Régnier <regnier@codelutin.com>
|
|
# Emmanuel Saracco <esaracco@easter-eggs.com>
|
|
#
|
|
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
|
|
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
|
|
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
|
|
# Emmanuel Saracco & Théridion
|
|
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
|
|
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
|
|
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
|
|
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
|
|
# Régnier, Emmanuel Saracco, Théridion & Vecam
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
__doc__ = """Glasnost Votes Web Proxy"""
|
|
|
|
__version__ = '$Revision$'[11:-2]
|
|
|
|
|
|
import cgi
|
|
import copy
|
|
|
|
import glasnost.common.context as context
|
|
import glasnost.common.faults as faults
|
|
import glasnost.common.slots as slots
|
|
import glasnost.common.tools_new as commonTools
|
|
|
|
from glasnost.proxy.VotesProxy import *
|
|
|
|
from ObjectsWeb import register, AdminWithoutWritersMixin, ObjectWebMixin, \
|
|
ObjectsWebMixin
|
|
from tools import *
|
|
import widgets
|
|
|
|
|
|
class AdminVotes(AdminWithoutWritersMixin, AdminVotes):
|
|
pass
|
|
register(AdminVotes)
|
|
|
|
|
|
class MarksWidget(widgets.BaseWidget):
|
|
def getModelHiddenLayout(self, slot, fields):
|
|
container = slot.getContainer()
|
|
idsGetterName = slot.getKind().idsGetterName
|
|
idsGetter = getattr(container, idsGetterName)
|
|
objectIds = idsGetter(fields)
|
|
layout = X.array()
|
|
marks = slot.getValue()
|
|
if objectIds:
|
|
for objectId in objectIds:
|
|
fieldName = slot.getFieldOptionName(objectId)
|
|
mark = ''
|
|
if marks and marks.has_key(objectId):
|
|
mark = str(marks[objectId])
|
|
layout += X.input(name = fieldName, type = 'hidden',
|
|
value = mark),
|
|
return layout
|
|
|
|
def submit(self, slot, fields):
|
|
container = slot.getContainer()
|
|
idsGetterName = slot.getKind().idsGetterName
|
|
idsGetter = getattr(container, idsGetterName)
|
|
objectIds = idsGetter(fields) or []
|
|
isBlank = isButtonSelected(
|
|
slot.getFieldOptionName('blankButton'), fields)
|
|
result = {}
|
|
if isBlank:
|
|
# why not returning an empty dictionary ?
|
|
for objectId in objectIds:
|
|
result[objectId] = 0
|
|
return result
|
|
|
|
for objectId in objectIds:
|
|
fieldName = slot.getFieldOptionName(objectId)
|
|
mark = self.submitOneMark(slot, objectId, fields)
|
|
result[objectId] = mark
|
|
return result
|
|
|
|
def submitOneMark(self, slot, objectId, fields):
|
|
mark = slot.getFieldOption(fields, objectId)
|
|
try:
|
|
return int(mark)
|
|
except ValueError:
|
|
return None
|
|
|
|
class VoteApprovalMarksWidget(MarksWidget):
|
|
def submitOneMark(self, slot, objectId, fields):
|
|
mark = slot.getFieldOption(fields, objectId)
|
|
if not mark:
|
|
mark = '0'
|
|
return int(mark)
|
|
|
|
def getHtmlFieldValue(self, slot, fields, **keywords):
|
|
marks = slot.getValue()
|
|
container = slot.getContainer()
|
|
idsGetterName = slot.getKind().idsGetterName
|
|
idsGetter = getattr(container, idsGetterName)
|
|
objectIds = idsGetter(fields)
|
|
if not self.isInForm():
|
|
if container.isAbstention():
|
|
return X.strong(_('Abstention'))
|
|
elif container.isBlank(objectIds):
|
|
return X.strong(_('Blank Vote'))
|
|
tdAttributes = {}
|
|
if self.colSpan:
|
|
tdAttributes['colspan'] = self.colSpan
|
|
layout = X.array()
|
|
if self.isReadOnly(slot):
|
|
layout += self.getModelHiddenLayout(slot, fields)
|
|
table = X.table(_class = 'vote')
|
|
layout += table
|
|
if objectIds:
|
|
for objectId in objectIds:
|
|
fieldName = slot.getFieldOptionName(objectId)
|
|
mark = 0
|
|
if marks and marks.has_key(objectId) and marks[objectId]:
|
|
mark = marks[objectId]
|
|
|
|
if mark:
|
|
markSymbol = 'x'
|
|
else:
|
|
markSymbol = X.nbsp
|
|
|
|
tr = X.tr()
|
|
table += tr
|
|
if not self.isInForm() or self.isReadOnly(slot):
|
|
tr += X.td( '[', markSymbol, ']',)
|
|
else:
|
|
td = X.td()
|
|
tr += td
|
|
error = slot.getObject().getError(slot.getPath())
|
|
if error and not context.getVar('hideErrors'):
|
|
td += X.span(_class = 'error-message')(
|
|
_(error.uiFaultString))
|
|
inputAttributes = {}
|
|
if mark:
|
|
inputAttributes['checked'] = 'checked'
|
|
td += X.input(name = fieldName, type = 'checkbox',
|
|
value = 1, **inputAttributes)
|
|
tr += X.td()(X.objectHypertextLabel(objectId))
|
|
return X.div(_class = 'cell')(layout)
|
|
widgets.register(VoteApprovalMarksWidget)
|
|
|
|
|
|
class VoteDistributionMarksWidget(MarksWidget):
|
|
def getHtmlFieldValue(self, slot, fields, **keywords):
|
|
marks = slot.getValue()
|
|
container = slot.getContainer()
|
|
idsGetterName = slot.getKind().idsGetterName
|
|
idsGetter = getattr(container, idsGetterName)
|
|
objectIds = idsGetter(fields)
|
|
if not self.isInForm():
|
|
if container.isAbstention():
|
|
return X.strong(_('Abstention'))
|
|
elif container.isBlank(objectIds):
|
|
return X.strong(_('Blank Vote'))
|
|
tdAttributes = {}
|
|
if self.colSpan:
|
|
tdAttributes['colspan'] = self.colSpan
|
|
layout = X.array()
|
|
if self.isReadOnly(slot):
|
|
layout += self.getModelHiddenLayout(slot, fields)
|
|
table = X.table(_class = 'vote')
|
|
layout += table
|
|
if objectIds:
|
|
for objectId in objectIds:
|
|
fieldName = slot.getFieldOptionName(objectId)
|
|
mark = ''
|
|
if marks and marks.has_key(objectId) and marks[objectId]:
|
|
mark = '%.2f' % (marks[objectId]*100)
|
|
tr = X.tr()
|
|
table += tr
|
|
tr += X.td(X.objectHypertextLabel(objectId), X.asIs(_(':')))
|
|
if not self.isInForm() or self.isReadOnly(slot):
|
|
tr += X.td()( mark, X.nbsp, '%',)
|
|
else:
|
|
td = X.td()
|
|
tr += td
|
|
error = slot.getObject().getError(slot.getPath())
|
|
if error and not context.getVar('hideErrors'):
|
|
td += X.span(_class = 'error-message')(
|
|
_(error.uiFaultString))
|
|
td += X.input(maxlength = 6, name = fieldName, size = 6,
|
|
type = 'text', value = mark)
|
|
td += X.nbsp
|
|
td += '%'
|
|
return X.div(_class = 'cell')(layout)
|
|
|
|
def submitOneMark(self, slot, objectId, fields):
|
|
mark = slot.getFieldOption(fields, objectId) or ''
|
|
if mark and mark.strip():
|
|
try:
|
|
mark = float(mark) / 100.
|
|
except ValueError:
|
|
raise faults.BadValue()
|
|
mark = 0
|
|
else:
|
|
mark = 0
|
|
|
|
return mark
|
|
|
|
widgets.register(VoteDistributionMarksWidget)
|
|
|
|
|
|
class VoteRankingMarksWidget(MarksWidget):
|
|
def getHtmlFieldValue(self, slot, fields, **keywords):
|
|
marks = slot.getValue()
|
|
container = slot.getContainer()
|
|
idsGetterName = slot.getKind().idsGetterName
|
|
idsGetter = getattr(container, idsGetterName)
|
|
objectIds = idsGetter(fields)
|
|
if not self.isInForm():
|
|
if container.isAbstention():
|
|
return X.strong(_('Abstention'))
|
|
elif container.isBlank(objectIds):
|
|
return X.strong(_('Blank Vote'))
|
|
layout = X.array()
|
|
if self.isReadOnly(slot):
|
|
layout += self.getModelHiddenLayout(slot, fields)
|
|
table = X.table(_class = 'vote')
|
|
layout += table
|
|
tdAttributes = {}
|
|
if self.colSpan:
|
|
tdAttributes['colspan'] = self.colSpan
|
|
if objectIds:
|
|
for objectId in objectIds:
|
|
fieldName = slot.getFieldOptionName(objectId)
|
|
|
|
mark = ''
|
|
if marks and marks.has_key(objectId) and marks[objectId]:
|
|
mark = marks[objectId]
|
|
mark = str(mark)
|
|
|
|
tr = X.tr()
|
|
table += tr
|
|
if not self.isInForm() or self.isReadOnly(slot):
|
|
tr += X.td( '[', X.nbsp, mark, X.nbsp, ']',)
|
|
else:
|
|
td = X.td()
|
|
tr += td
|
|
error = slot.getObject().getError(slot.getPath())
|
|
if error and not context.getVar('hideErrors'):
|
|
td += X.span(_class = 'error-message')(
|
|
_(error.uiFaultString))
|
|
maxLength = len(str(len(objectIds)))
|
|
td += X.input(
|
|
maxlength = maxLength, name = fieldName,
|
|
size = maxLength, type = 'text', value = mark)
|
|
tr += X.td(_class = 'field-label')(
|
|
X.objectHypertextLabel(objectId))
|
|
return X.div(_class = 'cell')(layout)
|
|
widgets.register(VoteRankingMarksWidget)
|
|
|
|
|
|
class VoteRatingMarksWidget(MarksWidget):
|
|
def getHtmlFieldValue(self, slot, fields, **keywords):
|
|
marks = slot.getValue()
|
|
container = slot.getContainer()
|
|
idsGetterName = slot.getKind().idsGetterName
|
|
idsGetter = getattr(container, idsGetterName)
|
|
objectIds = idsGetter(fields)
|
|
if not self.isInForm():
|
|
if container.isAbstention():
|
|
return X.strong(_('Abstention'))
|
|
elif container.isBlank(objectIds):
|
|
return X.strong(_('Blank Vote'))
|
|
tdAttributes = {}
|
|
if self.colSpan:
|
|
tdAttributes['colspan'] = self.colSpan
|
|
layout = X.array()
|
|
if self.isReadOnly(slot):
|
|
layout += self.getModelHiddenLayout(slot, fields)
|
|
table = X.table(_class = 'vote')
|
|
layout += table
|
|
if objectIds:
|
|
for objectId in objectIds:
|
|
fieldName = slot.getFieldOptionName(objectId)
|
|
mark = ''
|
|
if marks and marks.has_key(objectId) and marks[objectId]:
|
|
mark = marks[objectId]
|
|
tr = X.tr()
|
|
table += tr
|
|
tr += X.td()(X.objectHypertextLabel(objectId), X.asIs(_(':')))
|
|
if not self.isInForm() or self.isReadOnly(slot):
|
|
tr += X.td()(mark)
|
|
else:
|
|
td = X.td()
|
|
tr += td
|
|
error = slot.getObject().getError(slot.getPath())
|
|
if error and not context.getVar('hideErrors'):
|
|
td += X.span(_class = 'error-message')(
|
|
_(error.uiFaultString))
|
|
td += X.input(maxlength = 6, name = fieldName, size = 6,
|
|
type = 'text', value = mark)
|
|
return X.div(_class = 'cell')(layout)
|
|
widgets.register(VoteRatingMarksWidget)
|
|
|
|
|
|
class VoteMixin(ObjectWebMixin):
|
|
ballotKind_kind_widget_fieldLabel = N_('Kind of Ballot')
|
|
ballotKind_kind_widget_labels = {
|
|
'public': N_('Public Ballot'),
|
|
'secret': N_('Secret Ballot'),
|
|
}
|
|
ballotKind_kind_widgetName = 'Select'
|
|
|
|
comment_kind_widget_fieldLabel = N_('Comment')
|
|
comment_kind_widget_cols = 75
|
|
comment_kind_widget_colSpan = 2
|
|
comment_kind_widget_rows = 4
|
|
comment_kind_widgetName = 'TextArea'
|
|
|
|
#electionId_kind_hasToInitField = 0
|
|
#electionId_kind_hasToMakeFieldFromValue = 0
|
|
electionId_kind_hasToRepairField = 0
|
|
electionId_kind_hasToSubmitField = 0
|
|
electionId_kind_stateInEditMode = 'hidden'
|
|
electionId_kind_stateInViewMode = 'hidden'
|
|
electionId_kindName = 'Id'
|
|
electionId_kind_serverRoles = ['elections']
|
|
electionId_kind_widget_fieldLabel = N_('Election')
|
|
electionId_kind_widgetName = 'SelectId'
|
|
|
|
electionToken_kind_stateInEditMode = 'hidden'
|
|
electionToken_kind_stateInViewMode = 'hidden'
|
|
electionToken_kind_widget_fieldLabel = N_('Election Token')
|
|
electionToken_kind_widgetName = 'Token'
|
|
|
|
subject = None
|
|
subject_kind_isTranslatable = 0
|
|
subject_kind_stateInEditMode = 'read-only'
|
|
subject_kindName = 'String'
|
|
|
|
token_kind_stateInEditMode = 'read-only'
|
|
token_kind_widget_fieldLabel = N_('Vote Token')
|
|
token_kind_widgetName = 'Token'
|
|
|
|
#voterId_kind_hasToInitField = 0
|
|
#voterId_kind_hasToMakeFieldFromValue = 0
|
|
voterId_kind_hasToRepairField = 0
|
|
voterId_kind_hasToSubmitField = 0
|
|
voterId_kind_stateInEditMode = 'read-only'
|
|
voterId_kindName = 'Id'
|
|
voterId_kind_serverRoles = ['identities']
|
|
voterId_kind_widget_fieldLabel = N_('Voter')
|
|
voterId_kind_widgetName = 'SelectId'
|
|
|
|
voterToken_kind_stateInEditMode = 'read-only'
|
|
voterToken_kind_widget_fieldLabel = N_('Voter Token')
|
|
voterToken_kind_widgetName = 'Token'
|
|
|
|
def getElectionCandidateIds(self, fields):
|
|
return getObject(self.electionId).candidateIds
|
|
|
|
def getEditLayout(self, fields, parentSlot = None):
|
|
election = getObject(self.electionId)
|
|
slot = election.getSlot('subject')
|
|
translationsProxy = getProxyForServerRole('translations')
|
|
if translationsProxy:
|
|
subject, destinationLanguage, state = \
|
|
translationsProxy.getTranslationInfos(
|
|
election.subject, election.getId(), slot.getPath(),
|
|
election.getLanguage(), context.getVar('readLanguages'))
|
|
else:
|
|
subject = election.subject
|
|
self.subject = subject
|
|
self.subject_kind = copy.copy(election.subject_kind)
|
|
self.subject_kind.stateInEditMode = 'read-only'
|
|
self.subject_kind.isTranslatable = 0
|
|
self.subject_kind.widget = widgets.TextArea(
|
|
fieldLabel = N_('Subject'),
|
|
cols = 75,
|
|
colSpan = 2,
|
|
rows = 4)
|
|
|
|
layout = ObjectWebMixin.getEditLayout(
|
|
self, fields, parentSlot = parentSlot)
|
|
|
|
del self.subject
|
|
del self.subject_kind
|
|
|
|
return layout
|
|
|
|
def getEditLayoutHiddenSlotNames(self, fields, parentSlot = None):
|
|
hiddenSlotNames = ObjectWebMixin.getEditLayoutHiddenSlotNames(
|
|
self, fields, parentSlot = parentSlot)
|
|
hiddenSlotNames = hiddenSlotNames[:]
|
|
slot = self.getSlot('voterId')
|
|
if slot.getValue():
|
|
hiddenSlotNames.append('voterToken')
|
|
else:
|
|
hiddenSlotNames.append('voterId')
|
|
election = getObject(self.electionId)
|
|
if election.ballotKind != 'voterChoice':
|
|
hiddenSlotNames.append('ballotKind')
|
|
return hiddenSlotNames
|
|
|
|
def getViewLayout(self, fields, parentSlot = None):
|
|
election = getObject(self.electionId)
|
|
slot = election.getSlot('subject')
|
|
translationsProxy = getProxyForServerRole('translations')
|
|
if translationsProxy:
|
|
subject, destinationLanguage, state = \
|
|
translationsProxy.getTranslationInfos(
|
|
election.subject, election.getId(), slot.getPath(),
|
|
election.getLanguage(), context.getVar('readLanguages'))
|
|
else:
|
|
subject = election.subject
|
|
self.subject = subject
|
|
self.subject_kind = copy.copy(election.subject_kind)
|
|
self.subject_kind.isTranslatable = 0
|
|
self.subject_kind.widget = widgets.TextArea(
|
|
fieldLabel = N_('Subject'),
|
|
cols = 75,
|
|
colSpan = 2,
|
|
rows = 4)
|
|
|
|
layout = ObjectWebMixin.getViewLayout(
|
|
self, fields, parentSlot = parentSlot)
|
|
|
|
del self.subject
|
|
del self.subject_kind
|
|
|
|
return layout
|
|
|
|
def getViewLayoutHiddenSlotNames(self, fields, parentSlot = None):
|
|
hiddenSlotNames = ObjectWebMixin.getViewLayoutHiddenSlotNames(
|
|
self, fields, parentSlot = parentSlot)
|
|
hiddenSlotNames = hiddenSlotNames[:]
|
|
slot = self.getSlot('voterId')
|
|
if slot.getValue():
|
|
hiddenSlotNames.append('voterToken')
|
|
else:
|
|
hiddenSlotNames.append('voterId')
|
|
election = getObject(self.electionId)
|
|
if election.ballotKind != 'voterChoice':
|
|
hiddenSlotNames.append('ballotKind')
|
|
return hiddenSlotNames
|
|
|
|
|
|
class AbstractVote(VoteMixin, AbstractVote):
|
|
pass
|
|
register(AbstractVote)
|
|
|
|
|
|
class VoteApproval(VoteMixin, VoteApproval):
|
|
marks_kind_idsGetterName = 'getElectionCandidateIds'
|
|
marks_kindName = 'ApprovalMarks'
|
|
marks_kind_widget_fieldLabel = N_('Choice')
|
|
marks_kind_widgetName = 'VoteApprovalMarksWidget'
|
|
|
|
def getLabelLine(self, election):
|
|
if self.isAbstention():
|
|
line = '<i>%s</i>' % _('Abstention')
|
|
elif self.isBlank(election.candidateIds):
|
|
line = '<i>%s</i>' % _('Blank Vote')
|
|
else:
|
|
marks = self.getMarks(election.candidateIds)
|
|
candidates = [
|
|
getObjectLabelTranslated(
|
|
candidateId,
|
|
context.getVar('readLanguages'))
|
|
for candidateId in marks.keys()
|
|
if marks[candidateId]]
|
|
return ', '.join([cgi.escape(x) for x in candidates])
|
|
|
|
def getMarksRowLayout(self, candidateIds):
|
|
marks = self.getMarks(candidateIds)
|
|
layout = X.array()
|
|
for candidateId in candidateIds:
|
|
mark = marks[candidateId]
|
|
tdAttributes = {}
|
|
if mark:
|
|
red = 0
|
|
green = 255
|
|
cell = 'x'
|
|
else:
|
|
red = 255
|
|
green = 0
|
|
cell = X.nbsp
|
|
tdAttributes['style'] = 'background-color: #%(red)02x%(green)02x00' % {
|
|
'green': green,
|
|
'red': red,
|
|
}
|
|
layout += X.td(**tdAttributes)(cell)
|
|
return layout
|
|
register(VoteApproval)
|
|
|
|
|
|
class VoteDistribution(VoteMixin, VoteDistribution):
|
|
marks_kind_idsGetterName = 'getElectionCandidateIds'
|
|
marks_kindName = 'DistributionMarks'
|
|
marks_kind_widget_fieldLabel = N_('Choice')
|
|
marks_kind_widgetName = 'VoteDistributionMarksWidget'
|
|
|
|
def getLabelLine(self, election):
|
|
if self.isAbstention():
|
|
line = '<i>%s</i>' % _('Abstention')
|
|
elif self.isBlank(election.candidateIds):
|
|
line = '<i>%s</i>' % _('Blank Vote')
|
|
else:
|
|
line = ''
|
|
marks = self.getMarks(election.candidateIds)
|
|
candidateIds = marks.keys()[:]
|
|
def candidatesSorter(id1, id2, marks = marks):
|
|
return cmp(marks[id2], marks[id1])
|
|
candidateIds.sort(candidatesSorter)
|
|
for candidateId in candidateIds:
|
|
if line:
|
|
line = line + ', '
|
|
line = line + '%(candidate)s (%(mark)s)' % {
|
|
'candidate': cgi.escape(getObjectLabelTranslated(
|
|
candidateId, context.getVar('readLanguages'))),
|
|
'mark': marks[candidateId],
|
|
}
|
|
return line
|
|
|
|
def getMarksRowLayout(self, candidateIds):
|
|
marks = self.getMarks(candidateIds)
|
|
minMark = min(marks.values())
|
|
maxMark = max(marks.values())
|
|
if minMark < maxMark:
|
|
averageMark = (maxMark + minMark) / 2.0
|
|
coef = 255 / float(averageMark - minMark)
|
|
layout = X.array()
|
|
for candidateId in candidateIds:
|
|
mark = marks[candidateId]
|
|
tdAttributes = {}
|
|
if minMark < maxMark:
|
|
if mark <= averageMark:
|
|
red = 255
|
|
green = coef * (mark - minMark)
|
|
else:
|
|
red = coef * (maxMark - mark)
|
|
green = 255
|
|
tdAttributes['style'] = 'background-color: #%(red)02x%(green)02x00' % {
|
|
'green': green,
|
|
'red': red,
|
|
}
|
|
layout += X.td(**tdAttributes)(
|
|
'%.2f' % (mark * 100),
|
|
X.nbsp,
|
|
'%',
|
|
)
|
|
return layout
|
|
register(VoteDistribution)
|
|
|
|
|
|
class VoteRanking(VoteMixin, VoteRanking):
|
|
marks_kind_idsGetterName = 'getElectionCandidateIds'
|
|
marks_kindName = 'RankingMarks'
|
|
marks_kind_widget_fieldLabel = N_('Choice')
|
|
marks_kind_widgetName = 'VoteRankingMarksWidget'
|
|
|
|
def getLabelLine(self, election):
|
|
if self.isAbstention():
|
|
line = '<i>%s</i>' % _('Abstention')
|
|
elif self.isBlank(election.candidateIds):
|
|
line = '<i>%s</i>' % _('Blank Vote')
|
|
else:
|
|
line = ''
|
|
marks = self.getMarks(election.candidateIds)
|
|
candidateIds = marks.keys()[:]
|
|
def candidatesSorter(id1, id2, marks = marks):
|
|
return cmp(marks[id1], marks[id2])
|
|
candidateIds.sort(candidatesSorter)
|
|
for candidateId in candidateIds:
|
|
if line:
|
|
line = line + ', '
|
|
line = line + '(%(mark)s) %(candidate)s' % {
|
|
'candidate': cgi.escape(getObjectLabelTranslated(
|
|
candidateId, context.getVar('readLanguages'))),
|
|
'mark': marks[candidateId],
|
|
}
|
|
return line
|
|
|
|
def getMarksRowLayout(self, candidateIds):
|
|
marks = self.getMarks(candidateIds)
|
|
scores = self.getScores(candidateIds)
|
|
minScore = 0
|
|
maxScore = 1
|
|
if minScore < maxScore:
|
|
averageScore = (maxScore + minScore) / 2.0
|
|
coef = 255 / float(averageScore - minScore)
|
|
layout = X.array()
|
|
for candidateId in candidateIds:
|
|
mark = marks[candidateId]
|
|
tdAttributes = {}
|
|
if minScore < maxScore:
|
|
score = scores[candidateId]
|
|
if score <= averageScore:
|
|
red = 255
|
|
green = coef * (score - minScore)
|
|
else:
|
|
red = coef * (maxScore - score)
|
|
green = 255
|
|
tdAttributes['style'] = 'background-color: #%(red)02x%(green)02x00' % {
|
|
'green': green,
|
|
'red': red,
|
|
}
|
|
layout += X.td(**tdAttributes)(mark)
|
|
return layout
|
|
register(VoteRanking)
|
|
|
|
|
|
class VoteRating(VoteMixin, VoteRating):
|
|
marks_kind_idsGetterName = 'getElectionCandidateIds'
|
|
marks_kindName = 'RatingMarks'
|
|
marks_kind_widget_fieldLabel = N_('Choice')
|
|
marks_kind_widgetName = 'VoteRatingMarksWidget'
|
|
|
|
def getLabelLine(self, election):
|
|
if self.isAbstention():
|
|
line = '<i>%s</i>' % _('Abstention')
|
|
elif self.isBlank(election.candidateIds):
|
|
line = '<i>%s</i>' % _('Blank Vote')
|
|
else:
|
|
line = ''
|
|
marks = self.getMarks(election.candidateIds)
|
|
candidateIds = marks.keys()[:]
|
|
def candidatesSorter(id1, id2, marks = marks):
|
|
return cmp(marks[id2], marks[id1])
|
|
candidateIds.sort(candidatesSorter)
|
|
for candidateId in candidateIds:
|
|
if line:
|
|
line = line + ', '
|
|
line = line + '%(candidate)s (%(mark)s)' % {
|
|
'candidate': cgi.escape(getObjectLabelTranslated(
|
|
candidateId, context.getVar('readLanguages'))),
|
|
'mark': marks[candidateId],
|
|
}
|
|
return line
|
|
|
|
def getMarksRowLayout(self, candidateIds):
|
|
marks = self.getMarks(candidateIds)
|
|
minMark = 0
|
|
maxMark = 1
|
|
if minMark < maxMark:
|
|
averageMark = (maxMark + minMark) / 2.0
|
|
coef = 255 / float(averageMark - minMark)
|
|
layout = X.array()
|
|
for candidateId in candidateIds:
|
|
mark = marks[candidateId]
|
|
tdAttributes = {}
|
|
if minMark < maxMark:
|
|
if mark <= averageMark:
|
|
red = 255
|
|
green = coef * (mark - minMark)
|
|
else:
|
|
red = coef * (maxMark - mark)
|
|
green = 255
|
|
tdAttributes['style'] = 'background-color: #%(red)02x%(green)02x00' % {
|
|
'green': green,
|
|
'red': red,
|
|
}
|
|
layout += X.td(**tdAttributes)(
|
|
'%.2f' % (mark * 100))
|
|
return layout
|
|
register(VoteRating)
|
|
|
|
|
|
class VotesWeb(ObjectsWebMixin, VotesProxy):
|
|
def canAddObject(self, serverId = None):
|
|
return 0
|
|
|
|
def edit(self, id = '', electionId = ''):
|
|
ballotsWeb = getWebForServerRole('ballots')
|
|
electionsWeb = getWebForServerRole('elections')
|
|
identitiesWeb = getWebForServerRole('identities')
|
|
userId = context.getVar('userId', default = '')
|
|
userToken = context.getVar('userToken', default = '')
|
|
if not userToken:
|
|
return accessForbidden()
|
|
if id:
|
|
vote = ballotsWeb.getVote(id)
|
|
if vote == 'secret':
|
|
return accessForbidden()
|
|
rememberObject(id)
|
|
electionId = ballotsWeb.getElectionIdFromToken(
|
|
vote.electionToken, serverId = commonTools.extractServerId(id))
|
|
if not electionId \
|
|
or not electionsWeb.hasObject(electionId):
|
|
return pageNotFound()
|
|
if not electionsWeb.canVote(electionId):
|
|
return accessForbidden()
|
|
election = electionsWeb.getObject(electionId)
|
|
rememberObject(electionId)
|
|
else:
|
|
if not electionId \
|
|
or not electionsWeb.hasObject(electionId):
|
|
return pageNotFound()
|
|
if not electionsWeb.canVote(electionId):
|
|
return accessForbidden()
|
|
election = electionsWeb.getObject(electionId)
|
|
rememberObject(electionId)
|
|
voter = identitiesWeb.getObject(userId)
|
|
if voter.voteTokens is not None \
|
|
and voter.voteTokens.has_key(electionId):
|
|
voteToken = voter.voteTokens[electionId]
|
|
if voteToken == 'secret':
|
|
return accessForbidden()
|
|
try:
|
|
vote = ballotsWeb.getVoteFromToken(voteToken)
|
|
except faults.UnknownVoteToken:
|
|
vote = election.newVote()
|
|
vote.fillWithDefaultValues()
|
|
else:
|
|
id = vote.id
|
|
rememberObject(id)
|
|
else:
|
|
vote = election.newVote()
|
|
|
|
return self.editObject(vote, electionId)
|
|
edit.isPublicForWeb = 1
|
|
|
|
def editObject(self, vote, electionId = ''):
|
|
electionsWeb = getWebForServerRole('elections')
|
|
election = electionsWeb.getObject(electionId)
|
|
userId = context.getVar('userId', default = '')
|
|
vote.getSlot('electionId').setValue(electionId)
|
|
vote.getSlot('voterId').setValue(userId)
|
|
vote.getSlot('subject').setValue(election.subject)
|
|
|
|
if not vote.id:
|
|
headerTitle = _('New %s') % _(self.objectNameCapitalized)
|
|
else:
|
|
headerTitle = _('Editing %s - %s') % (
|
|
_(self.objectNameCapitalized), vote.getLabel())
|
|
|
|
context.push(_level = 'edit', layoutMode = 'edit')
|
|
try:
|
|
layout = X.array()
|
|
if context.getVar('error'):
|
|
layout += vote.getErrorLayout()
|
|
form = X.form(action = X.actionUrl('submit'),
|
|
enctype= 'multipart/form-data', method = 'post')
|
|
layout += form
|
|
|
|
slot = slots.Root(vote)
|
|
widget = slot.getWidget()
|
|
form += widget.getModelPageBodyLayout(slot, None)
|
|
|
|
buttonsBar = X.div(_class = 'buttons-bar')
|
|
form += buttonsBar
|
|
actionButtonsBar = X.span(_class = 'action-buttons-bar')
|
|
buttonsBar += actionButtonsBar
|
|
actionButtonsBar += X.buttonInForm('abstain', 'abstainButton')
|
|
actionButtonsBar += X.buttonInForm(
|
|
'vote-blank',
|
|
vote.getSlot('marks').getFieldOptionName('blankButton'))
|
|
actionButtonsBar += X.buttonInForm('vote', 'voteButton')
|
|
|
|
return writePageLayout(layout, headerTitle)
|
|
finally:
|
|
context.pull(_level = 'edit')
|
|
|
|
def submit(self, id = '', electionId = '', **keywords):
|
|
ballotsWeb = getWebForServerRole('ballots')
|
|
electionsWeb = getWebForServerRole('elections')
|
|
if keywords is None:
|
|
keywords = {}
|
|
userId = context.getVar('userId', default = '')
|
|
userToken = context.getVar('userToken', default = '')
|
|
if not userToken:
|
|
return accessForbidden()
|
|
if not electionId \
|
|
or not electionsWeb.hasObject(electionId):
|
|
return pageNotFound()
|
|
if not electionsWeb.canVote(electionId):
|
|
return accessForbidden()
|
|
if isButtonSelected('applyButton', keywords):
|
|
context.setVar('again', 1)
|
|
context.setVar('hideErrors', 1)
|
|
elif isButtonSelected('abstainButton', keywords):
|
|
try:
|
|
ballotsWeb.abstainForVote(electionId)
|
|
except faults.Fault:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
return redirect(X.actionUrl('view').add(
|
|
'electionId', electionId).add('voterId', userId))
|
|
election = electionsWeb.getObject(electionId)
|
|
vote = election.newVote()
|
|
vote.getSlot('electionId').setValue(electionId)
|
|
vote.submitFields(keywords)
|
|
if context.getVar('again'):
|
|
return self.editObject(vote, electionId)
|
|
try:
|
|
id = ballotsWeb.vote(electionId, vote)
|
|
except faults.WrongVersion:
|
|
context.setVar('error', 1)
|
|
vote.setError('version', 1)
|
|
return self.editObject(vote, electionId)
|
|
return redirect(X.idUrl(id))
|
|
submit.isPublicForWeb = 1
|
|
|
|
def view(self, id = '', electionId = '', voterId = ''):
|
|
ballotsWeb = getWebForServerRole('ballots')
|
|
electionsWeb = getWebForServerRole('elections')
|
|
identitiesWeb = getWebForServerRole('identities')
|
|
userId = context.getVar('userId', default = '')
|
|
if id:
|
|
vote = ballotsWeb.getVote(id)
|
|
if vote == 'secret':
|
|
return accessForbidden()
|
|
rememberObject(id)
|
|
electionId = ballotsWeb.getElectionIdFromToken(
|
|
vote.electionToken, serverId = commonTools.extractServerId(id))
|
|
if ballotsWeb.canGetVoteVoterId(id):
|
|
voterId = ballotsWeb.getVoteVoterId(id)
|
|
else:
|
|
voterId = ''
|
|
if not electionId \
|
|
or not electionsWeb.hasObject(electionId):
|
|
return pageNotFound()
|
|
if not electionsWeb.canGetObject(electionId):
|
|
return accessForbidden()
|
|
election = electionsWeb.getObject(electionId)
|
|
rememberObject(electionId)
|
|
else:
|
|
if not electionId \
|
|
or not electionsWeb.hasObject(electionId):
|
|
return pageNotFound()
|
|
if not voterId \
|
|
or not identitiesWeb.hasObject(voterId):
|
|
return pageNotFound()
|
|
if not electionsWeb.canGetObject(electionId):
|
|
return accessForbidden()
|
|
if not identitiesWeb.canGetObject(voterId):
|
|
return accessForbidden()
|
|
election = electionsWeb.getObject(electionId)
|
|
rememberObject(electionId)
|
|
voter = identitiesWeb.getObject(voterId)
|
|
if voter.voteTokens is not None \
|
|
and voter.voteTokens.has_key(electionId):
|
|
voteToken = voter.voteTokens[electionId]
|
|
if voteToken == 'secret':
|
|
return accessForbidden()
|
|
try:
|
|
vote = ballotsWeb.getVoteFromToken(voteToken)
|
|
except faults.UnknownVoteToken:
|
|
vote = election.newVote()
|
|
else:
|
|
id = vote.id
|
|
rememberObject(id)
|
|
else:
|
|
vote = election.newVote()
|
|
|
|
vote.getSlot('electionId').setValue(electionId)
|
|
vote.getSlot('voterId').setValue(userId)
|
|
vote.getSlot('subject').setValue(election.subject)
|
|
|
|
keywords = {}
|
|
|
|
label = election.getLabelTranslated(
|
|
context.getVar('readLanguages'))
|
|
|
|
layout = X.array()
|
|
slot = slots.Root(vote)
|
|
widget = slot.getWidget()
|
|
layout += widget.getModelPageBodyLayout(slot, None)
|
|
layout += X.br()
|
|
if voterId and voterId == userId and electionsWeb.canVote(electionId):
|
|
layout += X.buttonStandalone(
|
|
'edit',X.idUrl(id, 'edit').add('electionId', electionId))
|
|
layout += X.buttonStandalone(
|
|
_('Go to Election'), X.idUrl(electionId))
|
|
return writePageLayout(
|
|
layout, '%s - %s' % (_(self.objectNameCapitalized), label))
|
|
view.isPublicForWeb = 1
|
|
|
|
def viewAll(self):
|
|
context.push(_level = 'viewAll',
|
|
defaultDispatcherId = context.getVar('dispatcherId'))
|
|
try:
|
|
if not self.canGetObjects():
|
|
return accessForbidden()
|
|
layout = X.array()
|
|
|
|
if self.canGetAdmin():
|
|
layout += X.div(_class = 'buttons-bar')(
|
|
X.buttonStandalone('settings', X.actionUrl('admin')))
|
|
finally:
|
|
context.pull(_level = 'viewAll')
|
|
return writePageLayout(layout, _('Votes'))
|
|
viewAll.isPublicForWeb = 1
|
|
|