Esempio n. 1
0
    def get(self, linkKeyStr):

        if conf.isDev:
            logging.debug('SlicesFromCreator.get() linkKeyStr=' +
                          str(linkKeyStr))

        # Collect inputs
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         crumbRequired=False,
                                         signatureRequired=False)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Retrieve and check linkKey
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if conf.isDev:
            logging.debug('SlicesFromCreator.get() linkKeyRecord=' +
                          str(linkKeyRecord))
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.BUDGET_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        budgetId = linkKeyRecord.destinationId

        # Check that user is budget-creator
        budgetRecord = budget.Budget.get_by_id(int(budgetId))
        if conf.isDev:
            logging.debug('SlicesFromCreator.get() budgetRecord=' +
                          str(budgetRecord))
        if budgetRecord is None:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='budget is null')
        if (budgetRecord.creator != userId):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.NOT_OWNER)

        # Retrieve all slices for this budget and creator
        sliceRecords = slice.Slice.query(
            slice.Slice.budgetId == budgetId, slice.Slice.creator == userId,
            slice.Slice.fromEditPage == True).fetch()
        slicesByTitle = sorted(sliceRecords, key=lambda a: a.title)
        sliceDisplays = [
            httpServerBudget.sliceToDisplay(a, userId) for a in slicesByTitle
        ]

        # Display slices data
        responseData = {'success': True, 'slices': sliceDisplays}
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 2
0
    def get( self, linkKeyStr ):

        logging.debug( 'getBudget.GetBudget() linkKeyStr=' + linkKeyStr )

        # Collect inputs
        httpRequestId = os.environ.get( conf.REQUEST_LOG_ID )
        responseData = { 'success':False, 'httpRequestId':httpRequestId }

        cookieData = httpServer.validate( self.request, self.request.GET, responseData, self.response, idRequired=False )
        userId = cookieData.id()
        
        # Retrieve and check linkKey
        linkKeyRecord = linkKey.LinkKey.get_by_id( linkKeyStr )
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType != conf.BUDGET_CLASS_NAME):
            return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.BAD_LINK )
        budgetId = linkKeyRecord.destinationId

        # Retrieve Budget by id, filter/transform fields for display.
        budgetRecord = budget.Budget.get_by_id( int(budgetId) )
        logging.debug( 'GetBudgetData() budgetRecord=' + str(budgetRecord) )

        budgetDisp = httpServerBudget.budgetToDisplay( budgetRecord, userId )
        logging.debug( 'GetBudgetData() budgetDisp=' + str(budgetDisp) )
        
        linkKeyDisplay = httpServer.linkKeyToDisplay( linkKeyRecord )
        
        # Store budget to user's recent (cookie).
        user.storeRecentLinkKey( linkKeyStr, cookieData )

        # Display budget data.
        responseData = { 'success':True , 'linkKey':linkKeyDisplay , 'budget':budgetDisp }
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 3
0
    def post(self):
        logging.debug('DeleteAnswer.post() request.body=' + self.request.body)

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug('DeleteAnswer.post() inputData=' + str(inputData))

        linkKeyString = inputData['linkKey']
        answerId = inputData['answerId']
        browserCrumb = inputData.get('crumb', None)
        logging.debug('DeleteAnswer.post() browserCrumb=' + str(browserCrumb) +
                      ' linkKeyString=' + str(linkKeyString) + ' answerId=' +
                      str(answerId))

        responseData = {'success': False, 'requestLogId': requestLogId}
        cookieData = httpServer.validate(self.request, inputData, responseData,
                                         self.response)
        if not cookieData.valid(): return
        userId = cookieData.id()

        surveyId, loginRequired = retrieveSurveyIdFromLinkKey(
            cookieData, linkKeyString, responseData, self.response)
        if surveyId is None: return

        # Retrieve survey record to check survey creator
        surveyRec = survey.Survey.get_by_id(int(surveyId))
        if surveyRec is None:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='survey record not found')
        if surveyRec.creator != userId:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='surveyRec.creator != userId')

        # Delete old answer.
        if answerId:
            oldAnswerRec = answer.Answer.get_by_id(answerId)
            if oldAnswerRec is None:
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage='answer record not found')
            if oldAnswerRec.surveyId != surveyId:
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage='oldAnswerRec.surveyId != surveyId')
            oldAnswerRec.key.delete()

        # Display result.
        responseData.update({'success': True})
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 4
0
    def post(self):

        logging.debug( 'SignLoginRequest.post() request.body=' + self.request.body )

        # Collect inputs
        requestLogId = os.environ.get( conf.REQUEST_LOG_ID )
        responseData = { 'success':False, 'requestLogId':requestLogId }
        inputData = json.loads( self.request.body )
        logging.debug( 'SignLoginRequest.post() inputData=' + str(inputData) )

        loginRequestId = user.randomStringWithLength( conf.VOTER_ID_LOGIN_REQUEST_ID_LENGTH )
        signature = user.signLoginRequest( loginRequestId )

        # Store login-request-id, to later check against spoofed login-return
        cookieData = httpServer.validate( self.request, inputData, responseData, self.response )
        if not cookieData.browserId:  return
        browserId = cookieData.browserId

        browserRecord = browser.BrowserRecord.get_by_id( browserId )
        logging.debug( 'LoginReturn.post() browserRecord=' + str(browserRecord) )

        if not browserRecord:
            browserRecord = browser.BrowserRecord( id=browserId )
        now = int( time.time() )
        browserRecord.loginRequestTime = now
        browserRecord.voterLoginRequestId = loginRequestId
        browserRecord.put()

        responseData.update(  { 'success':True , 'loginRequestId':loginRequestId, 'signature':signature }  )
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 5
0
    def post(self):

        logging.debug('self.request=' + str(self.request))

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'requestLogId': requestLogId}
        inputData = json.loads(self.request.body)

        # Set cookie with signature based on browser-fingerprint from javascript
        cookieData = httpServer.validate(self.request,
                                         inputData,
                                         responseData,
                                         self.response,
                                         idRequired=False,
                                         makeValid=True)
        if not cookieData.valid():
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='cookieData invalid')
        responseData['success'] = True
        responseData['crumb'] = user.createCrumb(
            cookieData.browserId) if cookieData.valid() else ''

        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 6
0
    def post(self, linkKeyStr, proposalId):

        if conf.isDev:
            logging.debug('SuggestReasons.post() linkKeyStr=' +
                          str(linkKeyStr) + ' proposalId=' + str(proposalId))

        # Collect inputs
        inputData = json.loads(self.request.body)
        if conf.isDev:
            logging.debug('SuggestReasons.post() inputData=' + str(inputData))

        reasonStart = text.formTextToStored(inputData.get('content', ''))
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}
        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        if not reasonStart:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='Empty input')

        # Retrieve top-level records
        (linkKeyRecord, proposalRecord,
         requestRecord) = retrieveRequestAndProposal(linkKeyStr, proposalId)
        if not linkKeyRecord: return  # Bad link
        proposalId = str(proposalRecord.key.id())
        if proposalRecord.freezeUserInput or (requestRecord and
                                              requestRecord.freezeUserInput):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.FROZEN)

        # Retrieve reasons and vote, in parallel
        voteRecordsFuture = reasonVote.ReasonVote.query(
            reasonVote.ReasonVote.proposalId == proposalId,
            reasonVote.ReasonVote.userId
            == userId).fetch_async() if userId else None
        reasonRecords = reason.retrieveTopReasonsForStart(
            proposalId,
            reasonStart)  # Retrieve reasons while vote-record is retrieving
        voteRecords = voteRecordsFuture.get_result(
        ) if voteRecordsFuture else None

        # Filter/transform fields for display
        reasonDisps = [
            httpServer.reasonToDisplay(r, userId) for r in reasonRecords
        ]
        mergeReasonVotes(voteRecords, reasonDisps)

        # Display proposal data
        responseData = {'success': True, 'reasons': reasonDisps}
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 7
0
    def post(self):
        logging.debug('SubmitNewSurvey.post() request.body=' +
                      self.request.body)

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug('SubmitNewSurvey.post() inputData=' + str(inputData))

        introduction = text.formTextToStored(inputData.get('introduction', ''))
        browserCrumb = inputData.get('crumb', '')
        loginCrumb = inputData.get('crumbForLogin', '')
        loginRequired = inputData.get('loginRequired', False)
        logging.debug('SubmitNewSurvey.post() introduction=' +
                      str(introduction) + ' browserCrumb=' +
                      str(browserCrumb) + ' loginCrumb=' + str(loginCrumb) +
                      ' loginRequired=' + str(loginRequired))

        responseData = {'success': False, 'requestLogId': requestLogId}

        cookieData = httpServer.validate(self.request,
                                         inputData,
                                         responseData,
                                         self.response,
                                         loginRequired=loginRequired)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Check survey introduction length.
        if not httpServer.isLengthOk(introduction, '',
                                     conf.minLengthSurveyIntro):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.TOO_SHORT)

        # Construct and store new survey record.
        surveyRecord = survey.Survey(creator=userId,
                                     introduction=introduction,
                                     allowEdit=True)
        surveyRecordKey = surveyRecord.put()
        logging.debug('surveyRecordKey.id={}'.format(surveyRecordKey.id()))

        # Construct and store link key.
        surveyId = str(surveyRecordKey.id())
        linkKeyRecord = httpServer.createAndStoreLinkKey(
            conf.SURVEY_CLASS_NAME, surveyId, loginRequired, cookieData)

        # Display survey.
        surveyDisplay = httpServerAutocomplete.surveyToDisplay(
            surveyRecord, userId)
        linkKeyDisplay = httpServer.linkKeyToDisplay(linkKeyRecord)
        responseData.update({
            'success': True,
            'linkKey': linkKeyDisplay,
            'survey': surveyDisplay
        })
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 8
0
    def post(self):
        logging.debug( 'SubmitEditSurvey.post() request.body=' + self.request.body )

        # Collect inputs
        requestLogId = os.environ.get( conf.REQUEST_LOG_ID )
        inputData = json.loads( self.request.body )
        logging.debug( 'SubmitEditSurvey.post() inputData=' + str(inputData) )

        title = text.formTextToStored( inputData['title'] )
        introduction = text.formTextToStored( inputData['introduction'] )
        linkKeyString = inputData['linkKey']
        browserCrumb = inputData.get( 'crumb', '' )
        loginCrumb = inputData.get( 'crumbForLogin', '' )
        logging.debug( 'SubmitEditSurvey.post() introduction=' + str(introduction) + ' browserCrumb=' + str(browserCrumb) 
            + ' loginCrumb=' + str(loginCrumb) 
            + ' linkKeyString=' + str(linkKeyString) )

        responseData = { 'success':False, 'requestLogId':requestLogId }
        cookieData = httpServer.validate( self.request, inputData, responseData, self.response )
        if not cookieData.valid():  return
        userId = cookieData.id()

        # Retrieve link-key record
        if linkKeyString is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='linkKeyString is null' )
        linkKeyRecord = linkKey.LinkKey.get_by_id( linkKeyString )
        logging.debug( 'SubmitEditSurvey.post() linkKeyRecord=' + str(linkKeyRecord) )

        if linkKeyRecord is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='linkKey not found' )
        if linkKeyRecord.destinationType != conf.SURVEY_CLASS_NAME:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='linkKey destinationType=' + str(linkKeyRecord.destinationType) )
        surveyId = linkKeyRecord.destinationId
        loginRequired = linkKeyRecord.loginRequired

        if linkKeyRecord.loginRequired  and  not cookieData.loginId:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.NO_LOGIN )

        # Check survey length
        if not httpServer.isLengthOk( title, introduction, conf.minLengthSurveyIntro ):
            return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.TOO_SHORT )

        # Retrieve survey record.
        surveyRec = survey.Survey.get_by_id( int(surveyId) )
        logging.debug( 'SubmitEditSurvey.post() surveyRec=' + str(surveyRec) )

        if surveyRec is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='survey not found' )

        # Verify that survey is editable
        if userId != surveyRec.creator:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.NOT_OWNER )
        if not surveyRec.allowEdit:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.HAS_RESPONSES )

        # Update survey record
        surveyRec.title = title
        surveyRec.introduction = introduction
        surveyRec.put()
        
        # Display updated survey.
        surveyDisplay = httpServerAutocomplete.surveyToDisplay( surveyRec, userId )
        responseData.update(  { 'success':True, 'survey':surveyDisplay }  )
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 9
0
    def post(self):
        logging.debug('SetAnswer.post() request.body=' + self.request.body)

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug('SetAnswer.post() inputData=' + str(inputData))

        content = answer.standardizeContent(inputData.get('content', None))
        linkKeyString = inputData['linkKey']
        questionId = str(int(inputData['questionId']))
        browserCrumb = inputData.get('crumb', None)
        logging.debug('SetAnswer.post() content=' + str(content) +
                      ' browserCrumb=' + str(browserCrumb) +
                      ' linkKeyString=' + str(linkKeyString))

        responseData = {'success': False, 'requestLogId': requestLogId}
        cookieData = httpServer.validate(self.request, inputData, responseData,
                                         self.response)
        if not cookieData.valid(): return
        userId = cookieData.id()

        surveyId, loginRequired = retrieveSurveyIdFromLinkKey(
            cookieData, linkKeyString, responseData, self.response)
        if surveyId is None: return

        # Check answer length
        if (content is not None) and not httpServer.isLengthOk(
                content, '', conf.minLengthAnswer):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.TOO_SHORT)

        # Retrieve question record.
        questionRec = question.Question.get_by_id(int(questionId))
        logging.debug('SetAnswer.post() questionRec=' + str(questionRec))

        if questionRec is None:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='question not found')
        if questionRec.surveyId != surveyId:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='questionRec.surveyId != surveyId')

        # Update answer and vote.
        answerRec, voteRecord = answer.vote(questionId, surveyId, content,
                                            userId, questionRec.creator)

        # Display updated answer.
        responseData.update({'success': True, 'answerContent': content})
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 10
0
    def get(self, linkKeyStr):

        logging.debug(LogMessage('UserAnswers', 'linkKeyStr=', linkKeyStr))

        # Collect inputs.
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         crumbRequired=False,
                                         signatureRequired=False)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Retrieve and check linkKey.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.SURVEY_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        surveyId = linkKeyRecord.destinationId

        # Retrieve all answers for this survey and voter
        answerVoteRecs = answerVote.AnswerVote.query(
            answerVote.AnswerVote.surveyId == surveyId,
            answerVote.AnswerVote.userId == userId).fetch()
        logging.debug(
            LogMessage('UserAnswers', 'answerVoteRecs=', answerVoteRecs))

        answerRecordKeys = [
            ndb.Key(answer.Answer, a.answerId) for a in answerVoteRecs
            if (a is not None) and (a.answerId is not None)
        ]
        answerRecords = ndb.get_multi(answerRecordKeys)
        logging.debug(
            LogMessage('UserAnswers', 'answerRecords=', answerRecords))

        answerIdToContent = {a.key.id(): a.content for a in answerRecords if a}
        questionIdToAnswerContent = {
            v.questionId: answerIdToContent.get(v.answerId, None)
            for v in answerVoteRecs
        }

        # Display answers data.
        responseData.update({
            'success':
            True,
            'questionIdToAnswerContent':
            questionIdToAnswerContent
        })
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 11
0
    def get(self, linkKeyStr):

        if conf.isDev:
            logging.debug('SliceTitleResults.get() linkKeyStr=' +
                          str(linkKeyStr))

        # Collect inputs

        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        # No user-id required, works for any user with the link-key
        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        # Retrieve and check linkKey
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.BUDGET_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        budgetId = linkKeyRecord.destinationId

        # No need to enforce login-required in GET calls, only on write operations that create/use link-key
        # But enforcing here because the search is expensive
        if linkKeyRecord.loginRequired and not cookieData.loginId:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.NO_LOGIN)

        # Check that budget is valid
        budgetRecord = budget.Budget.get_by_id(int(budgetId))
        if budgetRecord is None:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='budget is null')

        # Retrieve best suggested slices for this slice-start
        maxTitles = 20  # With minimum-size 5%, cannot have more than 20 top slices
        titlesOrdered = slice.retrieveTopSliceTitlesByVotes(budgetId)
        if conf.isDev:
            logging.debug('SliceTitleResults.get() titlesOrdered=' +
                          str(titlesOrdered))

        # Display slices data
        titleDisplays = [t.toDisplay(userId) for t in titlesOrdered]
        responseData.update({'success': True, 'titles': titleDisplays})
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 12
0
    def post(self):

        logging.debug( 'LoginReturn.post() request.body=' + self.request.body )

        # Collect inputs
        requestLogId = os.environ.get( conf.REQUEST_LOG_ID )
        responseData = { 'success':False, 'requestLogId':requestLogId }
        inputData = urlparse.parse_qs( self.request.body )
        logging.debug( 'LoginReturn.post() inputData=' + str(inputData) )

        requestId = inputData['requestId'][0]
        responseSignature = inputData['responseSignature'][0]
        voterId = inputData['voterId'][0]
        city = inputData['city'][0]

        # Check that browser-id exists
        # Cannot check browser crumb/fingerprint, because they do not exist in the referring page
        # Send fingerprint via ajax before auto-closing tab
        cookieData = httpServer.validate( self.request, inputData, responseData, self.response, crumbRequired=False, signatureRequired=False )

        if not cookieData.browserId:  return
        browserId = cookieData.browserId

        # Check responseSignature
        expectedResponseSignature = user.signLoginResult( requestId, voterId, city )
        logging.debug( 'LoginReturn.post() expectedResponseSignature=' + str(expectedResponseSignature) )
        if (responseSignature != expectedResponseSignature):  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='responseSignature does not match expected' )

        # Check stored browserId -> loginRequestId , check timeout, then delete record
        browserRecord = browser.BrowserRecord.get_by_id( browserId )
        logging.debug( 'LoginReturn.post() browserRecord=' + str(browserRecord) )
        
        now = int( time.time() )
        if not browserRecord:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='login browserRecord=null' )
        if browserRecord.voterLoginRequestId != requestId:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='login requestId does not match expected' )
        if browserRecord.loginRequestTime + conf.VOTER_ID_TIMEOUT_SEC < now:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='login past timeout' )

        browserRecordKey = ndb.Key( browser.BrowserRecord, browserId )
        browserRecordKey.delete()

        # Send login-id to browser now, with response-page cookie, instead of server storing a mapping
        # To set crumbForLogin into original page's javascript variable, have to use separate getLoginCrumb call

        # Add voter-id to persistent cookie
        appVoterId = user.voterIdToApp( voterId )
        cookieData.dataNew[ conf.COOKIE_FIELD_VOTER_ID ] = appVoterId
        cookieData.dataNew[ conf.COOKIE_FIELD_VOTER_CITY ] = city

        # Send page that closes tab
        responseData.update( {
            'SITE_NAME': conf.SITE_NAME ,
            'crumb': user.createCrumb( browserId ) ,
            'city': city
        } )
        httpServer.outputTemplate( 'loginReturn.html', responseData, self.response, cookieData=cookieData )
Esempio n. 13
0
    def get(self, linkKeyStr):

        if conf.isDev:
            logging.debug('SlicesForUser.get() linkKeyStr=' + linkKeyStr)

        # Collect inputs
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         crumbRequired=False,
                                         signatureRequired=False)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Retrieve and check linkKey
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.BUDGET_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        budgetId = linkKeyRecord.destinationId

        # Retrieve all slices for this budget and voter
        sliceVoteRecord = slice.SliceVotes.get(budgetId, userId)
        sliceRecordKeys = [
            ndb.Key(slice.Slice, sliceId)
            for sliceId, size in sliceVoteRecord.slices.iteritems()
        ] if sliceVoteRecord else []
        sliceRecords = ndb.get_multi(sliceRecordKeys)
        if conf.isDev:
            logging.debug('SlicesForUser.get() sliceRecords=' +
                          str(sliceRecords))

        # TODO: If slice-record does not exist for slice in slice-votes... remove that vote

        sliceIdToDisplay = {
            s.key.id(): httpServerBudget.sliceToDisplay(s, userId)
            for s in sliceRecords if s
        }
        votesDisplay = httpServerBudget.sliceVotesToDisplay(
            sliceVoteRecord, userId)

        # Display slices data.
        responseData.update({
            'success': True,
            'slices': sliceIdToDisplay,
            'votes': votesDisplay
        })
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 14
0
    def get(self, linkKeyStr):

        logging.debug('GetSurveyQuestions.get() linkKeyStr=' + linkKeyStr)

        # Collect inputs.
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        # Retrieve and check linkKey.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.SURVEY_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        surveyId = linkKeyRecord.destinationId

        # Retrieve survey
        surveyRecord = survey.Survey.get_by_id(int(surveyId))
        if surveyRecord is None:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)

        # Retrieve all questions for this survey.
        questionRecords = question.Question.query(
            question.Question.surveyId == surveyId).fetch()

        # Order questions based on survey order
        questionIdToRec = {str(q.key.id()): q for q in questionRecords}
        questionsOrdered = [
            questionIdToRec.get(q, None) for q in surveyRecord.questionIds
        ]
        questionsOrdered = [q for q in questionsOrdered if q is not None]

        questionDisplays = [
            httpServerAutocomplete.questionToDisplay(q, userId)
            for q in questionsOrdered
        ]
        for q in range(len(questionDisplays)):
            questionDisplays[q]['positionInSurvey'] = q

        # Display questions data.
        responseData = {'success': True, 'questions': questionDisplays}
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 15
0
    def post(self):
        logging.debug(('SetAnswer', 'request.body=', self.request.body))

        # Collect inputs
        requestLogId = os.environ.get( conf.REQUEST_LOG_ID )
        inputData = json.loads( self.request.body )
        logging.debug(('SetAnswer', 'inputData=', inputData))

        content = answer.standardizeContent( inputData.get( 'content', None ) )
        linkKeyString = inputData['linkKey']
        questionId = str( int( inputData['questionId'] ) )
        browserCrumb = inputData.get( 'crumb', None )
        logging.debug(('SetAnswer', 'content=', content, 'browserCrumb=', browserCrumb, 'linkKeyString=', linkKeyString))

        responseData = { 'success':False, 'requestLogId':requestLogId }
        cookieData = httpServer.validate( self.request, inputData, responseData, self.response )
        if not cookieData.valid():  return
        userId = cookieData.id()

        # Retrieve link-key record
        surveyId, loginRequired = retrieveSurveyIdFromLinkKey( cookieData, linkKeyString, responseData, self.response )
        if surveyId is None:  return

        # Check answer length
        if ( content is not None ) and not httpServer.isLengthOk( content, '', conf.minLengthAnswer ):
            return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.TOO_SHORT )

        # Retrieve survey record to check whether survey is frozen
        surveyRec = survey.Survey.get_by_id( int(surveyId) )
        if surveyRec is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='survey record not found' )
        if surveyRec.freezeUserInput:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.FROZEN )

        # Require that answer and reason both exist, or both can be empty
        answerStr, reason = answer.parseAnswerAndReason( content )
        if surveyRec.hideReasons and reason:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='reasons hidden' )
        if (not answerStr) and reason:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.TOO_SHORT )
        if answerStr and (not reason) and (not surveyRec.hideReasons):  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.REASON_TOO_SHORT )

        # Retrieve question record.
        questionRec = question.Question.get_by_id( int(questionId) )
        logging.debug(('SetAnswer', 'questionRec=', questionRec))

        if questionRec is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='question not found' )
        if questionRec.surveyId != surveyId:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='questionRec.surveyId != surveyId' )
        
        # Update answer and vote.
        answerRec, voteRecord = answer.vote( questionId, surveyId, content, userId, questionRec.creator )

        # Display updated answer.
        responseData.update(  { 'success':True, 'answerContent':content }  )
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 16
0
    def get(self, linkKeyStr, questionId):

        logging.debug(LogMessage('UserAnswer', 'linkKeyStr=', linkKeyStr))

        # Collect inputs.
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         crumbRequired=False,
                                         signatureRequired=False)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Retrieve and check linkKey.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.SURVEY_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        surveyId = linkKeyRecord.destinationId

        # Retrieve all answers for this question and voter
        answerVoteRec = answerVote.get(questionId, userId)
        logging.debug(LogMessage('UserAnswer', 'answerVoteRec=',
                                 answerVoteRec))

        answerRecord = answer.Answer.get_by_id(answerVoteRec.answerId)
        logging.debug(LogMessage('UserAnswer', 'answerRecord=', answerRecord))

        if answerRecord.surveyId != surveyId:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='answerRecord.surveyId != surveyId')

        answerDisplay = httpServerAutocomplete.answerToDisplay(
            answerRecord, userId) if answerRecord else None

        # Display answers data.
        responseData.update({'success': True, 'answer': answerDisplay})
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 17
0
    def get(self):
        # Collect inputs
        responseData = { }
        cookieData = httpServer.validate( self.request, self.request.GET, responseData, self.response, crumbRequired=False, signatureRequired=False )
        if not cookieData.valid():  return

        # Retrieve link-key records from cookie.
        recentLinkKeyToTime = user.retrieveRecentLinkKeys( self.request )
        if recentLinkKeyToTime:
            recentLinkKeyRecordKeys = [ ndb.Key(conf.LINK_KEY_CLASS_NAME, k) for k in recentLinkKeyToTime ]
            recentLinkKeyRecords = ndb.get_multi( recentLinkKeyRecordKeys )

            destTypeXIdToLink = { '{}:{}'.format(k.destinationType, k.destinationId) : k.key.id()  for k in recentLinkKeyRecords if k }
            logging.debug( 'destTypeXIdToLink=' + str(destTypeXIdToLink) )
            
            # Retrieve link-key destination records.
            recentLinkKeyRecordsFiltered = [ r  for r in recentLinkKeyRecords if (r and (r.destinationType == requestForProposals.RequestForProposals.__name__ or r.destinationType == proposal.Proposal.__name__)) ]
            recentDestinationKeys = [ ndb.Key(r.destinationType, int(r.destinationId))  for r in recentLinkKeyRecordsFiltered ]
            recentDestinationRecords = ndb.get_multi( recentDestinationKeys )
            
            # Collect destination summaries.
            recentDestSummaries = []
            for r in recentDestinationRecords:
                if r is None:  continue
                destTypeAndId = '{}:{}'.format( r.key.kind(), r.key.id() )
                logging.debug( 'destTypeAndId=' + str(destTypeAndId) )
                
                linkKey = destTypeXIdToLink.get( destTypeAndId )
                logging.debug( 'linkKey=' + str(linkKey) )

                if not linkKey:  continue
                recentDestSummary = {'title':r.title, 'detail':r.detail, 'type':r.key.kind()}
                recentDestSummary['linkKey'] = linkKey
                recentDestSummary['time'] = recentLinkKeyToTime[ linkKey ]
                recentDestSummaries.append( recentDestSummary )
            logging.debug( 'getRecent.GetRecent() recentDestSummaries=' + str(recentDestSummaries) )
            
            # Order summaries by time.
            recentDestSummaries = sorted( [r for r in recentDestSummaries if r] , key=lambda r:r['time'] , reverse=True )

        else:
            recentDestSummaries = []

        logging.debug( 'getRecent.GetRecent() recentDestSummaries=' + str(recentDestSummaries) )
        
        responseData = { 'success':True, 'recents':recentDestSummaries }
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 18
0
    def get(self, linkKeyStr, questionId):

        logging.debug('GetQuestion.get() linkKeyStr=' + str(linkKeyStr) +
                      ' questionId=' + str(questionId))

        # Collect inputs.
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        # Retrieve and check linkKey.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.SURVEY_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        surveyId = linkKeyRecord.destinationId

        # Retrieve Question by id, filter/transform fields for display.
        questionRecord = question.Question.get_by_id(int(questionId))
        logging.debug('GetQuestion.get() questionRecord=' +
                      str(questionRecord))
        if questionRecord.surveyId != surveyId:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='questionRecord.surveyId != surveyId')

        questionDisp = httpServerAutocomplete.questionToDisplay(
            questionRecord, userId)
        logging.debug('GetQuestion.get() questionDisp=' + str(questionDisp))

        # Store question to user's recent (cookie).
        user.storeRecentLinkKey(linkKeyStr, cookieData)

        # Display question data.
        responseData = {'success': True, 'question': questionDisp}
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 19
0
    def post(self):
        logging.debug( 'FreezeSurvey.post() request.body=' + self.request.body )

        # Collect inputs
        requestLogId = os.environ.get( conf.REQUEST_LOG_ID )
        inputData = json.loads( self.request.body )
        logging.debug( 'FreezeSurvey.post() inputData=' + str(inputData) )

        linkKeyString = inputData['linkKey']
        freeze = bool( inputData['freeze'] )
        logging.debug( 'FreezeSurvey.post() freeze=' + str(freeze) + ' linkKeyString=' + str(linkKeyString) )

        responseData = { 'success':False, 'requestLogId':requestLogId }
        cookieData = httpServer.validate( self.request, inputData, responseData, self.response )
        if not cookieData.valid():  return
        userId = cookieData.id()

        # Retrieve link-key record
        if linkKeyString is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='linkKeyString is null' )
        linkKeyRecord = linkKey.LinkKey.get_by_id( linkKeyString )
        logging.debug( 'FreezeSurvey.post() linkKeyRecord=' + str(linkKeyRecord) )

        if linkKeyRecord is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='linkKey not found' )
        if linkKeyRecord.destinationType != conf.SURVEY_CLASS_NAME:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='linkKey destinationType=' + str(linkKeyRecord.destinationType) )
        surveyId = linkKeyRecord.destinationId
        loginRequired = linkKeyRecord.loginRequired

        if linkKeyRecord.loginRequired  and  not cookieData.loginId:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.NO_LOGIN )

        # Retrieve survey record
        surveyRec = survey.Survey.get_by_id( int(surveyId) )
        logging.debug( 'FreezeSurvey.post() surveyRec=' + str(surveyRec) )

        if surveyRec is None:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage='survey not found' )

        # Verify that survey is editable
        if userId != surveyRec.creator:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.NOT_OWNER )
        if not surveyRec.allowEdit:  return httpServer.outputJson( cookieData, responseData, self.response, errorMessage=conf.HAS_RESPONSES )

        # Update survey record
        surveyRec.freezeUserInput = freeze
        surveyRec.put()

        # Display updated survey
        surveyDisplay = httpServerAutocomplete.surveyToDisplay( surveyRec, userId )
        responseData.update(  { 'success':True, 'survey':surveyDisplay }  )
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 20
0
    def get(self, linkKeyStr, questionId):

        logging.debug(
            LogMessage('QuestionAnswersFromCreator', 'linkKeyStr=', linkKeyStr,
                       'questionId=', questionId))

        # Collect inputs.
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         crumbRequired=False,
                                         signatureRequired=False)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Retrieve and check linkKey.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord is None) or (linkKeyRecord.destinationType !=
                                       conf.SURVEY_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        surveyId = linkKeyRecord.destinationId

        # Retrieve all answers for this question and creator.
        answerRecords = answer.Answer.query(
            answer.Answer.questionId == questionId,
            answer.Answer.creator == userId,
            answer.Answer.fromEditPage == True).fetch()
        answersByContent = sorted(answerRecords, key=lambda a: a.content)
        answerDisplays = [
            httpServerAutocomplete.answerToDisplay(a, userId)
            for a in answersByContent
        ]

        # Display answers data.
        responseData = {'success': True, 'answers': answerDisplays}
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 21
0
    def post(self):

        logging.debug( 'SubmitLogout.post() request.body=' + self.request.body )

        # Collect inputs
        requestLogId = os.environ.get( conf.REQUEST_LOG_ID )
        responseData = { 'success':False, 'requestLogId':requestLogId }
        inputData = json.loads( self.request.body )
        logging.debug( 'SubmitLogout.post() inputData=' + str(inputData) )

        cookieData = httpServer.validate( self.request, inputData, responseData, self.response, crumbRequired=False, signatureRequired=False )
        if not cookieData.valid():  return   # Cookie already reset, no need to clear cookie fields

        # Remove voter-id from persistent cookie, even if cookie is already invalid
        cookieData.dataNew[ conf.COOKIE_FIELD_VOTER_ID ] = None
        cookieData.dataNew[ conf.COOKIE_FIELD_VOTER_CITY ] = None

        responseData.update(  { 'success':True }  )
        httpServer.outputJson( cookieData, responseData, self.response )
Esempio n. 22
0
    def get(self):

        logging.debug('GetRecent.get()')

        # Collect inputs
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        # No crumb because this is a get-call and we don't want to send crumb in the clear
        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         crumbRequired=False,
                                         signatureRequired=False)
        if not cookieData.valid(): return

        recentDestSummaries = []

        # Read recent link-keys from cookie
        recentLinkKeyToTime = user.retrieveRecentLinkKeys(self.request)
        if recentLinkKeyToTime:
            # Retrieve link-key records, using link-keys from cookie
            recentLinkKeyRecordKeys = [
                ndb.Key(linkKey.LinkKey, k) for k in recentLinkKeyToTime
            ]
            recentLinkKeyRecords = ndb.get_multi(recentLinkKeyRecordKeys)

            destSurveyIdToLink = {
                k.destinationId: k.key.id()
                for k in recentLinkKeyRecords if k
            }
            logging.debug('destSurveyIdToLink=' + str(destSurveyIdToLink))

            # Retrieve link-key destination records.
            recentDestinationKeys = [
                ndb.Key(survey.Survey, int(k.destinationId))
                for k in recentLinkKeyRecords if k
            ]
            recentDestinationRecords = ndb.get_multi(recentDestinationKeys)

            # Collect destination summaries.
            for r in recentDestinationRecords:
                if r is None: continue

                # Is there a better way to match link-key to dest type & id, without using string concat?
                # Use map[ linkKey -> dest type & id ] ?  No, dont have linkKey.
                # Don't need dest type, because all should be survey type.
                # Use tuple[type, id] ?

                link = destSurveyIdToLink.get(str(r.key.id()), None)
                logging.debug('link=' + str(link))

                if not link: continue
                recentDestSummary = {'introduction': r.introduction}
                recentDestSummary['linkKey'] = link
                recentDestSummary['time'] = recentLinkKeyToTime[link]
                recentDestSummaries.append(recentDestSummary)

            logging.debug('getRecent.GetRecent() recentDestSummaries=' +
                          str(recentDestSummaries))

            # Order summaries by time.
            recentDestSummaries = sorted([r for r in recentDestSummaries if r],
                                         key=lambda r: r['time'],
                                         reverse=True)

        logging.debug('getRecent.GetRecent() recentDestSummaries=' +
                      str(recentDestSummaries))

        responseData = {'success': True, 'recents': recentDestSummaries}
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 23
0
    def get(self, linkKeyStr, proposalId):

        if conf.isDev:
            logging.debug('TopReasons.get() linkKeyStr=' + str(linkKeyStr) +
                          ' proposalId=' + str(proposalId))

        # Collect inputs
        preview = self.request.get('preview', None) is not None
        cursorPro = self.request.get('cursorPro', None)
        cursorPro = Cursor(urlsafe=cursorPro) if cursorPro else None
        cursorCon = self.request.get('cursorCon', None)
        cursorCon = Cursor(urlsafe=cursorCon) if cursorCon else None
        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}
        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        # Retrieve top-level records
        (linkKeyRecord, proposalRecord,
         requestRecord) = retrieveRequestAndProposal(linkKeyStr, proposalId)
        if not linkKeyRecord: return  # Bad link
        proposalId = str(proposalRecord.key.id())

        # Retrieve reasons and vote, in parallel
        voteRecordsFuture = reasonVote.ReasonVote.query(
            reasonVote.ReasonVote.proposalId == proposalId,
            reasonVote.ReasonVote.userId
            == userId).fetch_async() if userId else None
        maxReasonsPerType = (conf.MAX_TOP_REASONS / 2) if preview else 10
        proRecordsFuture, conRecordsFuture = reason.retrieveTopReasonsAsync(
            proposalId,
            maxReasonsPerType,
            cursorPro=cursorPro,
            cursorCon=cursorCon)
        proRecords, cursorPro, morePros = proRecordsFuture.get_result()
        conRecords, cursorCon, moreCons = conRecordsFuture.get_result()
        cursorPro = cursorPro.urlsafe() if cursorPro else None
        cursorCon = cursorCon.urlsafe() if cursorCon else None
        voteRecords = voteRecordsFuture.get_result(
        ) if voteRecordsFuture else None

        # Filter/transform fields for display
        linkKeyDisplay = httpServer.linkKeyToDisplay(linkKeyRecord)
        proposalDisp = httpServer.proposalToDisplay(
            proposalRecord, userId, requestRecord=requestRecord)
        reasonDisps = [
            httpServer.reasonToDisplay(r, userId)
            for r in (proRecords + conRecords)
        ]
        mergeReasonVotes(voteRecords, reasonDisps)

        # Store request/proposal to user's recent (cookie)
        user.storeRecentLinkKey(linkKeyStr, cookieData)

        # Display proposal data
        responseData = {
            'success': True,
            'linkKey': linkKeyDisplay,
            'proposal': proposalDisp,
            'reasons': reasonDisps,
            'cursorPro': cursorPro,
            'cursorCon': cursorCon
        }
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 24
0
    def post(self):
        logging.debug(('EditSlice.post()', 'request.body=', self.request.body))

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug(('EditSlice.post()', 'inputData=', inputData))

        responseData = {'success': False, 'requestLogId': requestLogId}

        cookieData = httpServer.validate(self.request, inputData, responseData,
                                         self.response)
        if not cookieData.valid(): return
        userId = cookieData.id()

        title = slice.standardizeContent(
            text.formTextToStored(inputData['title']))
        reason = slice.standardizeContent(
            text.formTextToStored(inputData['reason']))
        linkKeyString = inputData['linkKey']
        sliceId = inputData.get('sliceId', None)  # Null if slice is new
        logging.debug(
            ('EditSlice.post()', 'sliceId=', sliceId, 'title=', title,
             'reason=', reason, 'linkKeyString=', linkKeyString))

        budgetId, loginRequired = retrieveBudgetIdFromLinkKey(
            cookieData, linkKeyString, responseData, self.response)
        if budgetId is None: return

        # Retrieve budget record to check budget creator
        budgetRec = budget.Budget.get_by_id(int(budgetId))
        if budgetRec is None:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='budget record not found')
        if budgetRec.creator != userId:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='budgetRec.creator != userId')

        # Check slice length
        if (not title) or (len(title) < conf.minLengthSliceTitle):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.TOO_SHORT)
        if budgetRec.hideReasons:
            if reason:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage='reasons hidden')
        else:
            if (not reason) or (len(reason) < conf.minLengthSliceTitle):
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage=conf.REASON_TOO_SHORT)

        # Delete old slice if it has no votes
        if sliceId:
            oldSliceRec = slice.Slice.get_by_id(sliceId)
            if oldSliceRec is None:
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage='slice record not found')
            if oldSliceRec.budgetId != budgetId:
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage='oldSliceRec.budgetId != budgetId')
            if oldSliceRec.creator != userId:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage=NOT_OWNER)
            if (oldSliceRec.voteCount <= 0):
                oldSliceRec.key.delete()

        # Create new slice only if there is existing record/vote
        sliceRec = slice.Slice.get(budgetId, title, reason)
        if sliceRec is None:
            sliceRec = slice.Slice.create(budgetId,
                                          title,
                                          reason,
                                          creator=userId)
        # Store slice record
        sliceRec.fromEditPage = True
        sliceRec.put()

        # Display updated slices
        sliceDisplay = httpServerBudget.sliceToDisplay(sliceRec, userId)
        responseData.update({'success': True, 'slice': sliceDisplay})
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 25
0
    def get(self, linkKeyStr, proposalId):

        logging.debug('getProposalData.GetProposalData() linkKeyStr=' +
                      linkKeyStr + ' proposalId=' + str(proposalId))

        # Collect inputs.
        onlyTopReasons = (self.request.get('onlyTop', None) == 'true')
        logging.debug('onlyTopReasons=' + str(onlyTopReasons))

        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        # Retrieve and check linkKey.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        requestId = None
        if linkKeyRecord is None:
            logging.debug('linkKeyRecord is None')
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        elif linkKeyRecord.destinationType == conf.PROPOSAL_CLASS_NAME:
            proposalId = linkKeyRecord.destinationId
        elif linkKeyRecord.destinationType == conf.REQUEST_CLASS_NAME:
            requestId = linkKeyRecord.destinationId
        else:
            logging.debug('linkKeyRecord has unhandled destinationType=' +
                          str(linkKeyRecord.destinationType))
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)

        # Retrieve Proposal by id, filter/transform fields for display.
        proposalRecord = proposal.Proposal.get_by_id(int(proposalId))
        logging.debug('GetProposalData() proposalRecord=' +
                      str(proposalRecord))
        if proposalRecord.requestId != requestId:
            logging.debug('proposalRecord.requestId=' +
                          str(proposalRecord.requestId) + '  !=  requestId=' +
                          str(requestId))
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)

        proposalDisp = httpServer.proposalToDisplay(proposalRecord, userId)
        logging.debug('GetProposalData() proposalDisp=' + str(proposalDisp))

        # Prepare parallel retrieve reasons, with votes.
        if onlyTopReasons:
            reasonRecordsFutures = reason.retrieveTopReasonsAsync(
                proposalId, conf.MAX_TOP_REASONS)
        else:
            reasonRecordsFutures = [
                reason.Reason.query(
                    reason.Reason.proposalId == proposalId).fetch_async()
            ]

        # If userId exists... retrieve user's ReasonVotes by KeyProperty proposalId x userId.
        voteRecordsFuture = reasonVote.ReasonVote.query(
            reasonVote.ReasonVote.proposalId == proposalId,
            reasonVote.ReasonVote.userId
            == userId).fetch_async() if userId else None

        # Run parallel retrieval.  Filter/transform fields for display.
        linkKeyDisplay = httpServer.linkKeyToDisplay(linkKeyRecord)
        logging.debug('GetProposalData() linkKeyDisplay=' +
                      str(linkKeyDisplay))

        reasonRecords = reason.fetchReasonRecordsFutures(reasonRecordsFutures)
        logging.debug('GetProposalData() reasonRecords=' + str(reasonRecords))

        reasonDisps = [
            httpServer.reasonToDisplay(r, userId) for r in reasonRecords
        ]
        logging.debug('GetProposalData() reasonDisps=' + str(reasonDisps))

        voteRecords = voteRecordsFuture.get_result(
        ) if voteRecordsFuture else None
        logging.debug('GetProposalData() voteRecords=' + str(voteRecords))

        # For each reason... lookup user vote ... set reason.myVote
        reasonToVoteRec = {v.reasonId: v
                           for v in voteRecords} if voteRecords else {}
        logging.debug('GetProposalData() reasonToVoteRec=' +
                      str(reasonToVoteRec))

        for r in reasonDisps:
            voteRec = reasonToVoteRec.get(r['id'])
            r['myVote'] = voteRec.voteUp if voteRec else False

        # Store proposal to user's recent (cookie).
        user.storeRecentLinkKey(linkKeyStr, cookieData)

        # Display proposal data.
        responseData = {
            'success': True,
            'linkKey': linkKeyDisplay,
            'proposal': proposalDisp,
            'reasons': reasonDisps,
        }
        logging.debug(
            'GetProposalData() responseData=' +
            json.dumps(responseData, indent=4, separators=(', ', ':')))
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 26
0
    def post(self, linkKeyStr):
        logging.debug('linkKeyStr=' + linkKeyStr)

        # Collect inputs
        inputData = json.loads(self.request.body)
        if conf.isDev:
            logging.debug('SuggestReasons.post() inputData=' + str(inputData))
        content = text.formTextToStored(inputData.get('content', ''))

        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        if not content:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='Empty input')

        # Retrieve link-record
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        if (linkKeyRecord == None) or (linkKeyRecord.destinationType !=
                                       conf.REQUEST_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)
        requestId = linkKeyRecord.destinationId

        # Retrieve RequestForProposal
        requestRecord = requestForProposals.RequestForProposals.get_by_id(
            int(requestId))
        if requestRecord and (requestRecord.freezeUserInput):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.FROZEN)

        # Retrieve Proposals
        proposalRecords = proposal.retrieveTopProposalsForStart(
            requestRecord.key.id(), content)

        linkKeyDisp = httpServer.linkKeyToDisplay(linkKeyRecord)
        requestDisp = httpServer.requestToDisplay(requestRecord, userId)
        proposalDisps = [
            httpServer.proposalToDisplay(p,
                                         userId,
                                         requestRecord=requestRecord)
            for p in proposalRecords
        ]

        # Display
        responseData = {
            'success': True,
            'linkKey': linkKeyDisp,
            'request': requestDisp,
            'proposals': proposalDisps
        }
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 27
0
    def get(self, linkKeyStr):
        logging.debug('linkKeyStr=' + linkKeyStr)

        # Collect inputs
        cursor = self.request.get('cursor', None)
        cursor = Cursor(urlsafe=cursor) if cursor else None
        getReasons = (self.request.get('getReasons', 'true') == 'true')
        logging.debug('getReasons=' + str(getReasons))

        httpRequestId = os.environ.get(conf.REQUEST_LOG_ID)
        responseData = {'success': False, 'httpRequestId': httpRequestId}

        cookieData = httpServer.validate(self.request,
                                         self.request.GET,
                                         responseData,
                                         self.response,
                                         idRequired=False)
        userId = cookieData.id()

        # Retrieve requestId from linkKey.  destinationType must be RequestForProposals.
        linkKeyRecord = linkKey.LinkKey.get_by_id(linkKeyStr)
        logging.debug('GetRequestData.get() linkKeyRecord=' +
                      str(linkKeyRecord))

        if (linkKeyRecord == None) or (linkKeyRecord.destinationType !=
                                       conf.REQUEST_CLASS_NAME):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.BAD_LINK)

        # Retrieve RequestForProposal by id, filter/transform fields for display.
        requestId = linkKeyRecord.destinationId
        requestRecordFuture = requestForProposals.RequestForProposals.get_by_id_async(
            int(requestId))

        requestRecord = requestRecordFuture.get_result(
        ) if requestRecordFuture else None

        logging.debug('GetRequestData.get() userId=' + str(userId) +
                      ' requestRecord.creator=' + str(requestRecord.creator))

        # If userId exists... async-retrieve user's ReasonVotes by KeyProperty requestId x userId.
        voteRecordsFuture = None
        if getReasons and userId:
            voteRecordsFuture = reasonVote.ReasonVote.query(
                reasonVote.ReasonVote.requestId == requestId,
                reasonVote.ReasonVote.userId == userId).fetch_async()

        # Retrieve Proposals by KeyProperty requestId
        # Get all data up to current page maximum length.  + Refreshes earlier proposal data.
        maxProposals = const.INITIAL_MAX_PROPOSALS
        proposalRecords, cursor, hasMore = proposal.retrieveTopProposals(
            requestId, maxProposals, cursor=cursor)
        cursor = cursor.urlsafe() if cursor else None

        # Async-retrieve top N reasons per proposal, equal number of pro/con reasons
        reasonRecordsFutures = []
        if getReasons:
            for proposalRec in proposalRecords:
                maxReasonsPerType = conf.MAX_TOP_REASONS / 2
                proRecordsFuture, conRecordsFuture = reason.retrieveTopReasonsAsync(
                    proposalRec.key.id(), maxReasonsPerType)
                reasonRecordsFutures.append(proRecordsFuture)
                reasonRecordsFutures.append(conRecordsFuture)

        # Wait for parallel retrievals
        logging.debug('GetRequestData.get() requestRecord=' +
                      str(requestRecord))

        reasonRecords = []
        for reasonRecordsFuture in reasonRecordsFutures:
            reasonRecordsForProp, cursor, hasMore = reasonRecordsFuture.get_result(
            )
            logging.debug('GetRequestData.get() reasonRecordsForProp=' +
                          str(reasonRecordsForProp))
            reasonRecords.extend(reasonRecordsForProp)
        reasonRecords = sorted(reasonRecords, key=lambda r: -r.score)
        logging.debug('GetRequestData.get() reasonRecords=' +
                      str(reasonRecords))

        voteRecords = voteRecordsFuture.get_result(
        ) if voteRecordsFuture else []
        logging.debug('GetRequestData.get() voteRecords=' + str(voteRecords))

        # Transform records for display.
        linkKeyDisp = httpServer.linkKeyToDisplay(linkKeyRecord)
        logging.debug('GetRequestData.get() linkKeyDisp=' + str(linkKeyDisp))

        requestDisp = httpServer.requestToDisplay(requestRecord, userId)
        logging.debug('GetRequestData.get() requestDisp=' + str(requestDisp))

        proposalDisps = [
            httpServer.proposalToDisplay(p,
                                         userId,
                                         requestRecord=requestRecord)
            for p in proposalRecords
        ]
        logging.debug('GetRequestData.get() proposalDisps=' +
                      str(proposalDisps))

        reasonDisps = [
            httpServer.reasonToDisplay(r, userId) for r in reasonRecords
        ]
        logging.debug('GetRequestData.get() reasonDisps=' + str(reasonDisps))

        # For each reason... collect user vote in reason.myVote
        reasonToVoteRec = {v.reasonId: v
                           for v in voteRecords} if voteRecords else {}
        logging.debug('GetRequestData.get() reasonToVoteRec=' +
                      str(reasonToVoteRec))

        for r in reasonDisps:
            voteRec = reasonToVoteRec.get(r['id'])
            r['myVote'] = voteRec.voteUp if voteRec else False

        # Store request to user's recent requests (cookie).
        user.storeRecentLinkKey(linkKeyStr, cookieData)

        # Display request data.
        responseData = {
            'success': True,
            'linkKey': linkKeyDisp,
            'request': requestDisp,
            'proposals': proposalDisps,
            'reasons': reasonDisps,
            'maxProposals': maxProposals,
            'cursor': cursor,
        }
        logging.debug(
            'GetRequestData.get() responseData=' +
            json.dumps(responseData, indent=4, separators=(', ', ':')))
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 28
0
    def post(self):
        logging.debug('SliceVote.post() request.body=' + self.request.body)

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug(('SliceVote.post()', 'inputData=', inputData))

        title = slice.standardizeContent(inputData.get('title', None))
        reason = slice.standardizeContent(inputData.get('reason', None))
        size = int(inputData.get('size', -1))
        linkKeyString = inputData['linkKey']
        sliceId = inputData.get('sliceId', None)
        logging.debug(('SliceVote.post()', 'title=', title, 'reason=', reason,
                       'linkKeyString=', linkKeyString))

        responseData = {'success': False, 'requestLogId': requestLogId}
        cookieData = httpServer.validate(self.request, inputData, responseData,
                                         self.response)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Enforce size limits
        if (size < conf.SLICE_SIZE_MIN) or (conf.SLICE_SIZE_MAX < size):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='Size out of bounds')

        # Retrieve link-key record
        budgetId, loginRequired = retrieveBudgetIdFromLinkKey(
            cookieData, linkKeyString, responseData, self.response)
        if budgetId is None: return

        # Retrieve budget record to check whether budget is frozen
        budgetRec = budget.Budget.get_by_id(int(budgetId))
        if budgetRec is None:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='budget record not found')
        if budgetRec.freezeUserInput:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.FROZEN)

        # Enforce minimum title/reason lengths
        if (title is None) or (len(title) < conf.minLengthSliceTitle):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.TOO_SHORT)
        if budgetRec.hideReasons:
            if reason:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage='reasons hidden')
        else:
            if (reason is None) or (len(reason) < conf.minLengthSliceReason):
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage=conf.TOO_SHORT)

        # Do not need to prevent duplicate titles here, because title & detail are already deduplicated by storage key
        # Storage-side deduplication would drop some user input, so have client-side warn if title is duplicate

        # Un-vote for old title and reason, if different
        newSliceId = slice.Slice.toKeyId(budgetId, title, reason)
        logging.debug(('SliceVote.post()', 'sliceId=', sliceId))
        logging.debug(('SliceVote.post()', 'newSliceId=', newSliceId))
        if sliceId and (sliceId != newSliceId):
            oldSliceRecord = slice.Slice.get_by_id(
                sliceId) if sliceId else None
            logging.debug(
                ('SliceVote.post()', 'oldSliceRecord=', oldSliceRecord))
            if oldSliceRecord:
                if (oldSliceRecord.budgetId != budgetId):
                    return httpServer.outputJson(
                        cookieData,
                        responseData,
                        self.response,
                        errorMessage='sliceId does not match budgetId')
                titleOld = oldSliceRecord.title
                reasonOld = oldSliceRecord.reason
                sliceRecord, voteRecord, success = slice.vote(
                    budgetId, titleOld, reasonOld, 0, userId)
                if not success:
                    return httpServer.outputJson(cookieData,
                                                 responseData,
                                                 self.response,
                                                 errorMessage='un-vote failed')

        # Update slice and vote
        sliceRecord, voteRecord, success = slice.vote(budgetId, title, reason,
                                                      size, userId)
        if not success:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.OVER_BUDGET)

        # Display updated slice
        sliceDisplay = httpServerBudget.sliceToDisplay(sliceRecord, userId)
        responseData.update({'success': success, 'slice': sliceDisplay})
        httpServer.outputJson(cookieData, responseData, self.response)
Esempio n. 29
0
    def post(self):

        logging.debug(
            LogMessage('SubmitNewReason', 'request.body=', self.request.body))

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug(LogMessage('SubmitNewReason', 'inputData=', inputData))

        linkKeyStr = inputData.get('linkKey', None)
        proposalId = str(int(inputData.get('proposalId', None)))
        proOrCon = inputData.get('proOrCon', None)
        reasonContent = text.formTextToStored(
            inputData.get('reasonContent', ''))
        browserCrumb = inputData.get('crumb', '')
        loginCrumb = inputData.get('crumbForLogin', '')
        logging.debug(
            LogMessage('SubmitNewReason', 'linkKeyStr=', linkKeyStr,
                       'proposalId=', proposalId, 'proOrCon=', proOrCon,
                       'reasonContent=', reasonContent, 'browserCrumb=',
                       browserCrumb, 'loginCrumb=', loginCrumb))

        # User id from cookie, crumb...
        responseData = {'success': False, 'requestLogId': requestLogId}
        cookieData = httpServer.validate(self.request, inputData, responseData,
                                         self.response)
        if not cookieData.valid(): return
        userId = cookieData.id()

        # Check reason length.
        if not httpServer.isLengthOk(reasonContent, '', conf.minLengthReason):
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.TOO_SHORT)

        # Retrieve link-key record
        linkKeyRec = linkKey.LinkKey.get_by_id(linkKeyStr)
        if linkKeyRec is None:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='linkKey not found')
        logging.debug(LogMessage('SubmitNewReason', 'linkKeyRec=', linkKeyRec))

        if linkKeyRec.loginRequired and not cookieData.loginId:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.NO_LOGIN)

        # Retrieve proposal record
        proposalRec = proposal.Proposal.get_by_id(int(proposalId))
        if proposalRec is None:
            return httpServer.outputJson(cookieDataresponseData,
                                         self.response,
                                         errorMessage='proposal not found')
        logging.debug(
            LogMessage('SubmitNewReason', 'proposalRec=', proposalRec))

        # Verify that reason belongs to linkKey's request/proposal, and check whether frozen
        requestId = None
        if linkKeyRec.destinationType == conf.PROPOSAL_CLASS_NAME:
            if proposalId != linkKeyRec.destinationId:
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage='proposalId != linkKeyRec.destinationId')
            if proposalRec.hideReasons:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage='reasons hidden')
            if proposalRec.freezeUserInput:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage=conf.FROZEN)

        elif linkKeyRec.destinationType == conf.REQUEST_CLASS_NAME:
            requestId = proposalRec.requestId
            if requestId != linkKeyRec.destinationId:
                return httpServer.outputJson(
                    cookieData,
                    responseData,
                    self.response,
                    errorMessage='requestId != linkKeyRec.destinationId')
            # Retrieve request-for-proposals, and check whether frozen
            requestRec = requestForProposals.RequestForProposals.get_by_id(
                int(requestId))
            if not requestRec:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage='requestRec is null')
            if requestRec.hideReasons:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage='reasons hidden')
            if requestRec.freezeUserInput:
                return httpServer.outputJson(cookieData,
                                             responseData,
                                             self.response,
                                             errorMessage=conf.FROZEN)

        else:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='linkKey destinationType=' +
                linkKeyRec.destinationType)

        # Retrieve any existing identical reason, to prevent duplicates
        existingReasons = reason.Reason.query(
            reason.Reason.requestId == requestId,
            reason.Reason.proposalId == proposalId,
            reason.Reason.proOrCon == proOrCon,
            reason.Reason.content == reasonContent).fetch(1)
        if existingReasons:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.DUPLICATE)

        # Construct new reason record
        reasonRecord = reason.Reason(requestId=requestId,
                                     proposalId=proposalId,
                                     creator=userId,
                                     proOrCon=proOrCon,
                                     allowEdit=True)
        reasonRecord.setContent(reasonContent)
        # Store reason record
        reasonRecordKey = reasonRecord.put()
        logging.debug(
            LogMessage('SubmitNewReason', 'reasonRecordKey=', reasonRecordKey))

        # Display reason
        reasonDisplay = httpServer.reasonToDisplay(reasonRecord, userId)
        responseData.update({'success': True, 'reason': reasonDisplay})
        httpServer.outputJson(cookieData, responseData, self.response)

        # Mark proposal as not editable.
        if proposalRec.allowEdit:
            proposal.setEditable(proposalId, False)
Esempio n. 30
0
    def post(self):
        logging.debug('SliceDelete.post() request.body=' + self.request.body)

        # Collect inputs
        requestLogId = os.environ.get(conf.REQUEST_LOG_ID)
        inputData = json.loads(self.request.body)
        logging.debug('SliceDelete.post() inputData=' + str(inputData))

        sliceId = inputData.get('sliceId', None)
        linkKeyString = inputData['linkKey']
        logging.debug('SliceDelete.post() + sliceId=' + str(sliceId) +
                      ' linkKeyString=' + str(linkKeyString))

        responseData = {'success': False, 'requestLogId': requestLogId}
        cookieData = httpServer.validate(self.request, inputData, responseData,
                                         self.response)
        if not cookieData.valid(): return
        userId = cookieData.id()

        if not sliceId:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='sliceId is null')

        # Retrieve link-key record
        budgetId, loginRequired = retrieveBudgetIdFromLinkKey(
            cookieData, linkKeyString, responseData, self.response)
        if budgetId is None: return

        # Retrieve slice-record to get title and reason
        sliceRecord = slice.Slice.get_by_id(sliceId)
        if conf.isDev:
            logging.debug('SliceSetSize.post() sliceRecord=' +
                          str(sliceRecord))
        if sliceRecord is None:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='slice record not found')
        if (sliceRecord.budgetId != budgetId):
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='sliceId does not match budgetId')
        title = sliceRecord.title
        reason = sliceRecord.reason

        # Retrieve budget record to check whether budget is frozen
        budgetRec = budget.Budget.get_by_id(int(budgetId))
        if budgetRec is None:
            return httpServer.outputJson(
                cookieData,
                responseData,
                self.response,
                errorMessage='budget record not found')
        if budgetRec.freezeUserInput:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage=conf.FROZEN)

        # Update slice-vote, and vote-aggregates
        size = 0
        sliceRecord, voteRecord, success = slice.vote(budgetId, title, reason,
                                                      size, userId)
        if conf.isDev:
            logging.debug('SliceSetSize.post() success=' + str(success) +
                          ' sliceRecord=' + str(sliceRecord) + ' voteRecord=' +
                          str(voteRecord))
        if not success:
            return httpServer.outputJson(cookieData,
                                         responseData,
                                         self.response,
                                         errorMessage='success is false')

        # Display result
        voteRecord = httpServerBudget.sliceVotesToDisplay(voteRecord, userId)
        responseData.update({'success': True, 'vote': voteRecord})
        httpServer.outputJson(cookieData, responseData, self.response)