def act(self, action, upload, upload_data, file_hash, designation, member, title=None): checkAuthor(action, member) checkNoUpload(upload, upload_data) fobj = RawFile.by_hash(file_hash) if fobj is None: raise ValidationError("File to publish does not exist.") mobj = fobj.proposal_metadata if mobj is None: raise ValidationError("File needs to have metadata.") if fobj.public(): raise ValidationError("File is already public.") nmobj = ProposalMetadata(filename=mobj.filename, mime_type=mobj.mime_type, designation=designation, title=title, raw_file=fobj, action=mobj.action, file_public=True) fobj.proposal_metadata = nmobj db.session.delete(mobj) db.session.add(nmobj)
def __init__(self, members, secretary, president, developer, previous=None): mnames = set(m.name for m in members) if len(mnames) < len(members): raise ValidationError("Duplicate members in list.") self.members = members self.secretary = secretary self.president = president self.developer = developer if secretary not in self.members: raise ValidationError("Secretary not listed as member.") if president not in self.members: raise ValidationError("President not listed as member.") if developer not in self.members: raise ValidationError("Developer not listed as member.") self.previous = previous self.xUpdate()
def cast(self, ballot, method_name, answer): log.debug("Casting new member vote: %s, %s, %s", ballot, method_name, answer) members_voted = set(b.author for b in self.ballots) if method_name != self.method_name: # should not happen - tVoteAnswer(..) should always set it correctly raise ValidationError("Wrong method '%s' expected '%s'." % (method_name, self.method_name)) if not self.is_open: raise ValidationError("Vote is not open anymore.") if ballot.member_list != self.action.member_list: # should not happen as votes need to be closed to create new member lists raise ValidationError( "Cannot vote on old proposal with different member list.") if ballot.author in members_voted: raise ValidationError("Member '%s' voted already." % ballot.author.name) if not ballot.author.eligible(): raise ValidationError("Member is not eligible to vote (anymore).") self.ballots.append(ballot) log.debug("Current ballot list: %s", self.ballots) self.xUpdate()
def act(self, action, upload, upload_data, meta_hash, member, method): method_name, method_options = method checkAuthor(action, member) checkNoUpload(upload, upload_data) mobj = ProposalMetadata.by_hash(meta_hash) if mobj is None: raise ValidationError("Proposal metadata '%s' does not exist." % meta_hash) if not mobj.file_public: raise ValidationError("Proposal needs to be published first.") fobj = mobj.raw_file if mobj.vote is not None: raise ValidationError("Vote already open for object '%s'/'%s'." % (fobj, mobj)) with db.session.no_autoflush: vobj = ProposalVote(fobj, mobj, action, method_name, method_options) robj = ProposalVoteResult(vobj) db.session.add(vobj) db.session.add(robj) return vobj
def cast(self, ballot, method_name, answer): log.debug("Casting vote: %s, %s, %s", ballot, method_name, answer) vote = self.vote members_voted = set(b.author for b in self.ballots) if not self.is_open: raise ValidationError("Vote is not open anymore.") # ----- # FIXME: temporary technical fix for social problem: # member keys and updates to member list are trickling in for this first vote # Temporary disable checking of proposal being generated for current member list # ----- #if ballot.member_list != vote.action.member_list: # raise ValidationError("Cannot vote on old proposal with different member list.") if ballot.author in members_voted: raise ValidationError("Member '%s' voted already." % ballot.author.name) if method_name != vote.method_name: # should not happen - tVoteAnswer(..) should always set it correctly raise ValidationError("Wrong method '%s' expected '%s'." % (method_name, vote.method_name)) if not ballot.author.eligible(): raise ValidationError("Member is not eligible to vote (anymore).") self.ballots.append(ballot) log.debug("Current ballot list: %s", self.ballots) self.xUpdate()
def tAddress(x): if len(x) > 35: raise ValidationError("Invalid address '%s' (too long)." % x) try: bitcoin.b58check_to_bin(x) except: raise ValidationError("Invalid address '%s'." % x) return x
def tDesignation(x): # designation for proposals if len(x) > 10: raise ValidationError("Invalid designation '%s' (too long)." % x) if not re.match("^[a-zA-Z0-9_-]+$", x): raise ValidationError("Invalid designation '%s'." % x) return x
def act(self, action, upload, upload_data, member, result_hash): checkAuthor(action, member) checkNoUpload(upload, upload_data) result = ProposalVoteResult.by_hash(result_hash) if result is None: raise ValidationError("Proposal result '%s' does not exist." % result_hash) if not result.is_open: raise ValidationError("Result is already closed.") result.close()
def tMemberName(x): if len(x) > 30: raise ValidationError("Invalid member name '%s' (too long)." % x) if not re.match("^[a-zA-Z0-9_-]+$", x): raise ValidationError("Invalid member name '%s'." % x) if x in ["president", "developer", "secretary"]: raise ValidationError( "Invalid member name '%s'. Can't be any of the official BU rules." % x) return x
def tAccRejAbs(x): """ A value accept, reject or accept, returned as string. """ if x in ["accept", "reject", "abstain", "spoil"]: return x else: raise ValidationError( "Expected accept, reject or abstain (or spoil), got '%s'." % x)
def tYesNo(x): """ A boolean, specified as yes(true) or no(false). """ if x == "yes": return True elif x == "no": return False else: raise ValidationError("Expected yes or no, got '%s'." % x)
def __init__(self, data=None): self.data = data dhash = hashlib.sha256(data).hexdigest() orf = RawFile.by_hash(dhash) if orf is not None: raise ValidationError("Raw file with hash '%s' exists already." % dhash) self.xUpdate()
def act(self, action, upload, upload_data, name, address, member): checkAuthor(action, member) checkNoUpload(upload, upload_data) with db.session.no_autoflush: if Member.by_name(name) is not None: raise ValidationError("Member '%s' exists already." % name) if Member.by_address(address) is not None: raise ValidationError( "Member '%s' already uses address '%s'." % (Member.by_address(address).name, address)) m = Member(name=name, address=address) nme = MemberElectionResult(m, action) db.session.add(m) db.session.add(nme)
def act(self, action, upload, upload_data, hashes, member): checkAuthor(action, member) checkNoUpload(upload, upload_data) all_objects = get_all_objects() objects = set() objs_ext = set() # go through list of objects and add them plus all immediate # dependencies to objs_ext, plus do some sanity checks # FIXME: inefficient! for hash in hashes: if hash not in all_objects: raise ValidationError("Object with hash %s not found." % hash) obj = all_objects[hash] if obj == Global.current_member_list(): raise ValidationError( "Objects cannot be deleted as list contains the current member list." ) objects.add(obj) objs_ext.add(obj) for user in users_of(obj): objs_ext.add(user) # now compare - if they are not the same, the votemaster has not # explicitly listed all relevant objects for deletion, which is # regarded as an error to avoid mistakes if objects != objs_ext: raise ValidationError( "Set of objects to delete is not including all dependencies.", error_page={ "template": "error_delete_objects_mismatch.html", "action": action, "objects": objects, "ext_objs": objs_ext, "missing": objs_ext - objects }) for obj in objects: db.session.delete(obj)
def __call__(self, s): sanitize_input(s) shl = shlex.shlex(s) shl.wordchars += "-%:" try: tokens = list(shl) except ValueError: raise ValidationError("Parse error.") return self.parse(tokens)
def __init__(self, vote): if vote is None: raise ValidationError("Vote needed.") if vote.result is not None: raise ValidationError("Vote already has a result attached.") self.vote = vote with db.session.no_autoflush: self.Nmemb_eligible_opened = sum( member.eligible() for member in vote.action.member_list.members) self.is_open = True self.reconstruct() self.xUpdate()
def tSafeString(x): """ String that hopefully cannot be used to render any HTML/JS tricks. FIXME: review! """ if x[0] == "'": if x[-1] != "'": raise ValidationError( "String starting with \"'\" needs to end with \"'\".") elif x[0] == '"': if x[-1] != '"': raise ValidationError( "String starting with '\"' needs to end with '\"'.") else: raise ValidationError("Please put string in quote marks.") x = x[1:-1] if not re.match("^[a-zA-Z0-9_ .:;!?+\-*/#@%=^\(\)\[\]\$]*$", x): raise ValidationError("Unsafe string '%s'." % x) return x
def set_member_last_vote_time(args): import time import dbenv member = Member.by_name(args.name) if member is None: raise ValidationError("No recent member '%s' exists." % args.name) Global.set_member_last_vote_time( member, time.mktime(time.strptime(args.last_vote_time, "%d-%m-%Y"))) db.session.commit()
def act(self, action, upload, upload_data, vote_hash, member, answer_tuple): from vote_methods import vote_methods method_name, answer = answer_tuple checkAuthor(action, member) checkNoUpload(upload, upload_data) vote = ProposalVote.by_hash(vote_hash) if vote is None: # pragma: no cover # should not happen as voteanswer type check checks that vote_hash is valid implicitly raise ValidationError("Vote '%s' does not exist." % vote_hash) if vote.result is None: # pragma: no cover # should never happen as all proposal votes are created # with result object attached and SQLAlchemy should check this raise ValidationError("Vote result does not exist.") vote.result.cast(action, method_name, answer)
def __init__(self, raw_file, proposal_metadata, action, method_name, method_options): if proposal_metadata.vote is not None: raise ValidationError("Vote on proposal(metadata) that " + "has already a vote attached.") self.raw_file = raw_file self.proposal_metadata = proposal_metadata self.action = action self.method_name = method_name self.method_options = method_options self.xUpdate()
def tVoteMethod(context, tokens): from vote_methods import vote_methods methodname = tokens[0] tokens = tokens[1:] if methodname not in vote_methods: raise ValidationError("Invalid voting method '%s'." % methodname) method = vote_methods[methodname]() ae = AExpr(method.spec_template, atypes) avars = ae.parse(tokens) method.checkSpecification(**avars) return (methodname, avars)
def addMember(name, address, pgp_pubkey, number, last_vote_time): ml = Global.current_member_list() if len(list(ml.applications())): raise ValidationError("Current member list has new members applying.") if name in [m.name for m in ml.members]: raise ValidationError("Member '%s' exists in current member list." % name) member = Member.by_name(name) if member is not None: raise ValidationError("Recent member '%s' exists." % name) new_member = Member(name=name, address=address, pgp_pubkey=pgp_pubkey, number=number) hmember = Member.by_hash(new_member.hashref()) if hmember is not None: # FIXME: maybe implement pointing to old member definition here log.info("Use existing member with same info.") new_member = hmember new_memberlist = ml.members.copy() new_memberlist.append(new_member) new_memberlist = MemberList(members=new_memberlist, secretary=ml.secretary, president=ml.president, developer=ml.developer, previous=ml) if hmember is None: db.session.add(new_member) db.session.add(new_memberlist) db.session.flush() # need to flush so that Global.set* works below Global.set_member_last_vote_time(new_member, last_vote_time) Global.set_current_member_list(new_memberlist)
def __init__(self, action): self.action = action s = action.actstr.find(" ") act = action.actstr[:s] if act not in action_map: raise ValidationError("Unknown action '%s'." % act) self.act = act self.ae = action_map[act]() self.expr = aparser.AExpr(self.ae.template, atypes) self.actvars = self.expr(action.actstr[s + 1:])
def act(self, action, upload, upload_data, new_number, membername, votemaster): checkAuthor(action, votemaster) checkNoUpload(upload, upload_data) if new_number <= 0: raise ValidationError( "Member number must be set to a positive number, not %d." % new_number) member = Member.by_name(membername) updateMemberinCurrentMemberList(membername, "unchanged", "unchanged", new_number)
def act(self, action, upload, upload_data, name, address, member, answer_tuple): method_name, answer = answer_tuple checkAuthor(action, member) checkNoUpload(upload, upload_data) member = Member.by_name(name) if member is None: raise ValidationError("Member '%s' not found." % name) if member.address != address: raise ValidationError( "Address '%s' for new member '%s' different from expected '%s'." % (address, name, member.address)) election = MemberElectionResult.by_member(member) if election is None: raise ValidationError("No election for member '%s' exists." % member.name) election.cast(action, method_name, answer)
def tVoteAnswer(context, tokens): # FIXME: code duplication from tproposalvote import ProposalVote from vote_methods import vote_methods if "vote_hash" not in context: raise ValidationError("Expected 'vote_hash' in context.") vote = ProposalVote.by_hash(context["vote_hash"]) if vote is None: raise ValidationError("Vote '%s' does not exist." % context["vote_hash"]) method_name = vote.method_name if method_name not in vote_methods: raise ValidationError("Invalid voting method '%s'." % method_name) method = vote_methods[method_name]() ae = AExpr(method.vote_template, atypes) avars = ae.parse(tokens) method.checkAnswer(vote, **avars) return (method_name, avars)
def act(self, action, upload, upload_data, pubkey_hash, membername, votemaster): checkAuthor(action, votemaster) checkUpload(upload, upload_data) dhash = hashlib.sha256(upload_data).hexdigest() if dhash != pubkey_hash: raise ValidationError( "Uploaded PGP key data data has hash %s but expected %s as in action." % (fobj.hashref(), file_hash)) updateMemberinCurrentMemberList(membername, "unchanged", upload_data.decode("ascii"), "unchanged")
def __init__(self, new_member, action): # FIXME: might be too stringent (re-joining members etc.?) review if len(new_member.member_lists): # should have been tested in actionexec already raise ValidationError("Member is already member of a member list.") self.new_member = new_member self.action = action with db.session.no_autoflush: self.Nmemb_eligible_opened = sum( member.eligible() for member in action.member_list.members) self.is_open = True self.reconstruct() self.xUpdate()
def act(self, action, upload, upload_data, names, member): checkAuthor(action, member) checkNoUpload(upload, upload_data) ml = Global.current_member_list() mers = ml.applications() names = set(names) app_names = set(a.new_member.name for a in mers) if app_names != names: raise ValidationError( "Currently, all new member elections must be closed at once.") members_voted_in = dict((r.new_member.name, r.new_member) for r in mers if r.summarize()["accepted"]) new_members = [] # loop over names given to close-member-election action to keep the # order (member numbers) intact for name in names: if name in members_voted_in: m = members_voted_in[name] # "deprecate" tempory member objects used for voting m.most_recent = False # create new members - with auto-assigned member numbers new_members.append( Member(name=m.name, address=m.address, pgp_pubkey=m.pgp_pubkey, number="assign-new")) new_memberlist = MemberList(members=ml.members + new_members, secretary=ml.secretary, president=ml.president, developer=ml.developer, previous=ml) for mer in mers: mer.close() db.session.add(new_memberlist) Global.set_current_member_list(new_memberlist)
def tVoteMaster(membername): vmr = Global.get_votemaster_roles() if membername in vmr: # member is listed directly? -> pass return membername cml = Global.current_member_list() # FIXME: factor some stuff out here if ((cml.president.name == membername and "president" in vmr) or (cml.secretary.name == membername and "secretary" in vmr) or (cml.developer.name == membername and "developer" in vmr)): # listed as any of the official roles -> pass return membername raise ValidationError("Member '%s' needs to be vote master." % membername)