def validate_election(parameters, existing_election=None): """ Validate an election's parameters based on constraints. :param parameters: The election's parameters. :param existing_election: An existing election to not compare against during validation. :return: None """ # check if start and end are valid datetime strings try: datetime.strptime(parameters['start'], datetime_format) datetime.strptime(parameters['end'], datetime_format) except ValueError as e: raise exceptions.BadRequest400Exception(e.message) # checking that election doesn't start or end in the past now = datetime.now().strftime(datetime_format) if parameters['start'] < now or parameters['end'] < now: raise exceptions.Forbidden403Exception('election takes place during the past') # check that end time isn't less than start time if parameters['start'] > parameters['end']: raise exceptions.Forbidden403Exception('start time is after end time') # check that election doesn't overlap with current or upcoming elections if elections_alchemy.detect_election_overlap(parameters["start"], parameters["end"], existing_election): raise exceptions.Forbidden403Exception('election takes place during another election') # check that max_votes is at least one if int(parameters['max_votes']) < 1: raise exceptions.Forbidden403Exception('max_votes must be at least one')
def validate_ballot(parameters): """ Validate a ballot's parameters based on constraints. :param parameters: The ballot's parameters. :return: None """ # check if election exists specified_election = elections_alchemy.query_election(election_id=parameters['election']) if specified_election == list(): raise exceptions.NotFound404Exception('election with specified ID not found') # check if position exists and is active specified_position = elections_alchemy.query_position(position_id=parameters['position']) if specified_position == list() or specified_position[0].active is False: raise exceptions.Forbidden403Exception('position with specified ID not found') # check if position is the right election type if specified_position[0].election_type != specified_election[0].election_type: raise exceptions.Forbidden403Exception('you are creating a vote for a position in a different election type') # check for valid candidate username if mask_alchemy.query_by_username(parameters['vote']) is None: raise exceptions.Forbidden403Exception('you cannot create a vote for this candidate') # check for duplicate votes if elections_alchemy.query_vote(election_id=specified_election[0].id, position_id=specified_position[0].id, vote=parameters['vote'], username=parameters['username']) != list(): raise exceptions.Forbidden403Exception('this candidate has already been voted for by this user')
def get(self, election_id): # get current user user = self.current_user # get election election = elections_alchemy.query_election(election_id=election_id) if election == list(): raise exceptions.NotFound404Exception('election with specified ID not found') election = election[0] # check if results should not be sent is_admin = user is not None and (admin_permission in user.roles or elections_permission in user.roles) if not is_admin and (election.show_results is None or datetime.now() < election.show_results): raise exceptions.Forbidden403Exception('results are not available for this election') # count votes for each position position_totals = list() for position in elections_alchemy.query_position(election_type=election.election_type, active=True): # add each position to the totals position_summary = { 'position': position.id, 'votes': elections_alchemy.count_votes(election_id, position.id) } position_totals.append(position_summary) # response self.set_status(200) self.write({'positions': [position for position in position_totals]})
def validate_vote(parameters, existing_vote=None): """ Validate a vote's parameters based on constraints. :param parameters: The vote's parameters. :param existing_vote: An existing vote being updated used to check for duplicate votes. :return: None """ # check if election exists specified_election = elections_alchemy.query_election(election_id=parameters['election']) if specified_election == list(): raise exceptions.NotFound404Exception('election with specified ID not found') # check if not current election current_election = elections_alchemy.query_current() if specified_election[0] != current_election: raise exceptions.Forbidden403Exception('this election is not available for voting') # check if position exists and is active specified_position = elections_alchemy.query_position(position_id=parameters['position']) if specified_position == list() or specified_position[0].active is False: raise exceptions.Forbidden403Exception('position with specified ID not found') # check if position is the right election type if specified_position[0].election_type != current_election.election_type: raise exceptions.Forbidden403Exception('you are voting for a position in a different election type') # check for valid candidate username if mask_alchemy.query_by_username(parameters['vote']) is None: raise exceptions.Forbidden403Exception('you cannot vote for this person') # check for duplicate votes if parameters['vote'] != getattr(existing_vote, 'vote', None) and \ elections_alchemy.query_vote(election_id=specified_election[0].id, position_id=specified_position[0].id, vote=parameters['vote'], username=parameters['username']) != list(): raise exceptions.Forbidden403Exception('you have already voted for this person')
def wrapper(self, *args, **kwargs): user = getattr(self, 'current_user') # check permission_or perm_found = True for perm in perm_args: if perm not in user.roles: perm_found = False # check for admin if admin_permission in user.roles: perm_found = True # raise exception if no permission is found if not perm_found: raise exceptions.Forbidden403Exception('you do not have permission to do this') # call method return func(self, *args, **kwargs)
def validate_position(parameters): """ Validate a position's parameters based on constraints. :param parameters: The position's parameters. :return: None """ # check active parameter's type if not isinstance(parameters['active'], bool): raise exceptions.BadRequest400Exception('parameter active has type bool') # check order parameter's type if not isinstance(parameters['order'], int): raise exceptions.BadRequest400Exception('parameter order has type integer') # check that order parameter is >= 0 if parameters['order'] < 0: raise exceptions.Forbidden403Exception('parameter order must be greater than or equal to 0')
def post(self, election_id): # get current user user = self.current_user # load request body body = self.request.body.decode('utf-8') body_json = json.loads(body) # validate parameters required_parameters = ('election', 'position', 'student_id', 'vote') elections_validator.validate_parameters(body_json, required_parameters) # get student username from student ID voter = mask_alchemy.query_by_wwuid(mask_model.User, body_json['student_id']) if voter == list(): raise exceptions.NotFound404Exception('user with specified student ID not found') voter = voter[0] # build proper vote from ballot data and validate it body_json['election'] = str(election_id) body_json['username'] = str(voter.username) body_json['manual_entry'] = str(user.username) elections_validator.validate_ballot(body_json) # check for too many votes specified_election = elections_alchemy.query_election(election_id=body_json['election']) specified_position = elections_alchemy.query_position(position_id=body_json['position']) if len(elections_alchemy.query_vote(election_id=specified_election[0].id, position_id=specified_position[0].id, username=str(voter.username))) >= specified_election[0].max_votes: raise exceptions.Forbidden403Exception( 'this user has already cast {} vote/s'.format(str(specified_election[0].max_votes)) ) # create new vote vote = elections_model.Vote() for parameter in required_parameters: if parameter != 'student_id': setattr(vote, parameter, body_json[parameter]) setattr(vote, 'username', str(voter.username)) setattr(vote, 'manual_entry', str(user.username)) elections_alchemy.add_or_update(vote) # response self.set_status(201) self.write(vote.serialize_ballot())
def post(self, wwuid): """ Modify roles in the users table, accessible only in a testing environment. Writes the modified user object. """ if not environment['pytest']: raise exceptions.Forbidden403Exception('Method Forbidden') else: user = mask.query_user(wwuid) if user == list(): exceptions.NotFound404Exception( 'user with specified wwuid not found') else: body = self.request.body.decode('utf-8') body_json = json.loads(body) user.roles = ','.join(body_json['roles']) mask.add_or_update(user) self.set_status(201) self.write({'user': user.to_json()})
def delete(self, vote_id): # get vote vote = elections_alchemy.query_vote(vote_id=str(vote_id)) if vote == list(): raise exceptions.NotFound404Exception('vote with specified ID not found') vote = vote[0] # get election election = elections_alchemy.query_election(election_id=str(vote.election))[0] # dont allow deleting past candidates if election != elections_alchemy.query_current(): raise exceptions.Forbidden403Exception('vote not in the current election') # delete the vote elections_alchemy.delete(vote) # response self.set_status(204)
def post(self): # get current user user = self.current_user # load request body body = self.request.body.decode('utf-8') body_json = json.loads(body) # validate parameters required_parameters = ('election', 'position', 'vote') elections_validator.validate_parameters(body_json, required_parameters) body_json['username'] = str(user.username) elections_validator.validate_vote(body_json) # check for too many votes specified_election = elections_alchemy.query_election(election_id=body_json['election']) specified_position = elections_alchemy.query_position(position_id=body_json['position']) if len(elections_alchemy.query_vote(election_id=specified_election[0].id, position_id=specified_position[0].id, username=str(user.username))) > specified_election[0].max_votes: raise exceptions.Forbidden403Exception( 'you may only cast {} vote/s'.format(str(specified_election[0].max_votes)) ) if specified_election[0].election_type == 'senate': votes = elections_alchemy.query_vote(election_id=specified_election[0].id, username=str(user.username)) for vote in votes: if vote.position != body_json['position']: elections_alchemy.delete(vote) # create new vote vote = elections_model.Vote() for parameter in required_parameters: setattr(vote, parameter, body_json[parameter]) setattr(vote, 'username', str(user.username)) elections_alchemy.add_or_update(vote) # response self.set_status(201) self.write(vote.serialize())
def get(self, vote_id): # get current user user = self.current_user # get current election current_election = elections_alchemy.query_current() if current_election is None: raise exceptions.Forbidden403Exception('there is currently no open election') # get vote vote = elections_alchemy.query_vote(vote_id=str(vote_id), election_id=current_election.id, username=str(user.username)) # validate vote ID if vote == list(): raise exceptions.NotFound404Exception('vote with specified ID not found') # response self.set_status(200) self.write(vote[0].serialize())
def delete(self, election_id, candidate_id): # get candidate candidate = elections_alchemy.query_candidates(election_id=str(election_id), candidate_id=str(candidate_id)) if candidate == list(): raise exceptions.NotFound404Exception('candidate with specified ID not found') candidate = candidate[0] # get election election = elections_alchemy.query_election(election_id=str(election_id)) if election == list(): raise exceptions.NotFound404Exception('election with specified ID not found') election = election[0] # dont allow deleting past candidates if election != elections_alchemy.query_current_or_upcoming(): raise exceptions.Forbidden403Exception('candidate not in the current or upcoming election') # delete the candidate elections_alchemy.delete(candidate) # response self.set_status(204)
def validate_candidate(parameters): """ Validate a candidate's parameters based on constraints. :param parameters: The candidate's parameters. :return: None """ # check to make sure there is an election to push candidates to election = elections_alchemy.query_election(election_id=parameters['election']) if election == list(): raise exceptions.NotFound404Exception('election with specified ID not found') election = election[0] # check to make sure election is either current or up and coming if election != elections_alchemy.query_current() and \ election not in elections_alchemy.query_election(start_after=datetime.now()): raise exceptions.Forbidden403Exception('candidate not in current election') # check to makes sure position exists if not elections_alchemy.query_position(position_id=str(parameters["position"])): raise exceptions.NotFound404Exception('position with specified ID not found') # check to make sure election exists if not elections_alchemy.query_election(election_id=parameters['election']): raise exceptions.NotFound404Exception('election with specified ID not found')
def put(self, vote_id): # get current user user = self.current_user # load request body body = self.request.body.decode('utf-8') body_json = json.loads(body) # get current election current_election = elections_alchemy.query_current() if current_election is None: exceptions.Forbidden403Exception('there is currently no open election') # get vote vote = elections_alchemy.query_vote(vote_id=vote_id, election_id=current_election.id, username=str(user.username)) if vote == list(): raise exceptions.NotFound404Exception('vote with specified ID not found') vote = vote[0] # validate parameters required_parameters = ('id', 'election', 'position', 'vote', 'username') elections_validator.validate_parameters(body_json, required_parameters) body_json['username'] = str(user.username) elections_validator.validate_vote(body_json, vote) # update vote for parameter in required_parameters: if parameter not in ('id', 'username'): setattr(vote, parameter, body_json[parameter]) setattr(vote, 'username', str(user.username)) elections_alchemy.add_or_update(vote) # response self.set_status(200) self.write(vote.serialize())