| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- import time
- import pprint
- from datetime import datetime
- class Chain():
-
- def __init__(self):
-
- # initialize the mock blockchain
- self.blockchain = []
- self.current_block = Block()
-
- # add old block to chain and create new block
- def new_block(self):
- self.blockchain.append(self.current_block)
- self.current_block = Block()
- pass
-
- # create new contract
- def new_contract(self,client, contractor, deadline, discription, name, price, people, initiator):
-
- n_contracts = 0
- for block in self.blockchain + [self.current_block]:
- for item in block.block:
- if item['type'] == 'init':
- n_contracts += 1
- # set discriptors of contract
- contract = {'id':n_contracts,
- 'type':'init',
- 'date of initiation':get_t(),
- 'initiated by': initiator,
- 'data': {'client':client,
- 'contractor':contractor,
- 'discription':discription,
- 'name':name,
- 'people': people},
- 'terms' : {'deadline': deadline,
- 'accepted': False,
- 'progress': '0%',
- 'price':price,
- 'Sign time': 'not yet signed',
- 'comments':{}
- }
- }
-
- # add as transaction
- self.current_block.add(contract)
-
- # If block to big, get new
- if self.current_block.size() > 10:
- self.new_block()
-
- # add updates to the contract
- def update_contract(self, iden, attr, value, by, comment=None):
-
- # check if transaction adds or modifies
- self.current_contract_state(iden)
- if attr in self.state['data'] or attr in self.state['terms']:
- t = 'modify'
- else: t = 'update'
-
- # add new or updated info to block
- update = {'id':iden,
- 'update id':len(self.get_updates(iden)),
- 'updated':attr,
- 'type':t,
- 'last update':get_t(),
- 'updated by':by,
- 'accepted': False,
- 'change':{attr:value}}
-
- # check if comment is passed and add it if necassary
- if comment:
- update['comment'] = comment
-
- # add transaction
- self.current_block.add(update)
-
- # check if new block is needed
- if self.current_block.size() > 10:
- self.new_block()
-
- # accept updates
- def accept_update(self, iden, update_id, awnser, by, comment=None):
- update = {
- 'id':iden,
- 'update id':update_id,
- 'accept':awnser,
- 'type':'accept',
- 'last update':get_t(),
- 'accepted by': by
- }
- if comment:
- update['comment'] = comment
-
- self.current_block.add(update)
-
- # check if new block is needed
- if self.current_block.size() > 10:
- self.new_block()
-
- # get current state of the contract
- def current_contract_state(self, iden):
- # set up contract state
- self.state = {'id':iden,
- 'data':{},
- 'terms':{}
- }
-
- b = []
-
- # loop over all blocks in the chain
- for block in self.blockchain:
- b += block.block
-
- # retreive all the data
- transactions = b + self.current_block.block
-
- # save not yet approved updates
- updates = {}
-
- # loop over all transaction in block
- for item in transactions:
-
- # save data about our project
- if item['id'] == iden:
- # set state to inital contract state
- if item['type'] == 'init':
- self.state = item
- continue
- # if update is not accept update, save it to updates dict
- if item['type'] != 'accept':
-
- # comments are always accepted
- if item['updated'] != 'comments':
- updates[item['update id']] = item
- continue
-
- # if accepted is true, retrieve update form dict and add to contract state
- elif item['accept'] == True:
- item = updates[item['update id']]
-
- # set attr to whatever has been updated
- attr = item['updated']
-
- # check if the update was removal
- if item['type'] == 'remove':
-
- # delete item in the right part of the dict
- try:
- if attr in self.state['data']:
- del self.state['data'][attr]
- else:
- del self.state['terms'][attr]
- except:
- pass
-
- if item['type'] == 'update':
- self.state['terms'][attr] = item['change'][attr]
-
- # check if updated attr is data or terms
- elif attr in self.state['data']:
- self.state['data'][attr] = item['change'][attr]
-
- elif attr in self.state['terms']:
-
- # special case for comments
- if attr == 'comments' and item['type'] not in ['remove', 'init']:
-
- k = list(item['change'][attr].keys())[0]
- self.state['terms'][attr][k] = item['change'][attr][k]
-
- # case for normal updates
- else:
- self.state['terms'][attr] = item['change'][attr]
-
- # special cases for last update and date of initiation
- elif 'last update' in item:
- self.state['last update'] = item['last update']
-
- # get updates based on contract, atribute updated or accept state
- def get_updates(self, iden=None, attr=None, accepted=None):
- updates = []
-
- # get all blocks and loop over transactions
- for block in self.blockchain + [self.current_block]:
- for item in block.block:
-
- # if attr is '' get updates for all attributes
- if attr == None:
-
- # if iden is None, get updates for all contracts
- # updates for all contracts and attrs
- if iden == None:
- if item['type'] != 'init':
- updates.append(item)
-
- # updates for specific contracts from all attr
- else:
- if item['type'] != 'init' and item['id'] == iden:
- updates.append(item)
- else:
-
- # updates for specific attrs from all contract
- if iden == None:
- if item['type'] != 'init' and item['updated'] == attr:
- updates.append(item)
- # updates for specific contract and specific attr
- else:
- if item['type'] != 'init' and item['updated'] == attr and item['id'] == iden:
- updates.append(item)
- return updates
-
- # add transaction to remove items
- def remove_item(self, iden, attr):
-
- # add transaction to remove item
- self.current_block.add({'id':iden,
- 'updated':attr ,
- 'type':'remove',
- 'last update':get_t(),
- 'accept':False,
- 'update id':len(self.get_updates(iden))})
-
- if self.current_block.size() > 10:
- self.new_block()
-
- # add comments to
- def add_comment(self, iden, body, author):
-
- # get all updates for comments
- comment_updates = []
- for block in self.blockchain + [self.current_block]:
- for item in block.block:
- if 'updated' in item:
- if item['updated'] == 'comments' and item['id'] == iden:
- comment_updates.append(item)
-
- # create transaction
- to_add = {'id':iden,
- 'updated':'comments',
- 'accept':True,
- 'type':'modify',
- 'last update':get_t(),
- 'change':{'comments':{len(comment_updates):{'author':author,
- 'body': body,
- 'time': get_t(),
- 'contract':iden}}}}
- self.current_block.add(to_add)
- if self.current_block.size() > 10:
- self.new_block()
-
- # retrieve comments based on author and contract
- def retrieve_comments(self, iden=None, author = None):
- comment = []
-
- # check every block in the chain
- for block in self.blockchain + [self.current_block]:
- for item in block.block:
-
- # if transaction is of type init, skip it
- if item['type'] == 'init' or item['type'] == 'accept':
- continue
-
- # check if the update is a comment
- if item['updated'] == 'comments':
-
- #filters for contract and author
- # no contract or author filter
- if iden == None and author == None:
- comment.append(item['change']['comments'])
- # filter by contract
- elif iden != None and author == None:
- if item['id'] == iden:
- comment.append(item['change']['comments'])
-
- # filter by author
- elif iden == None and author != None:
- if list(item['change']['comments'].values())[0]['author'] == author:
- comment.append(item['terms']['comments'])
-
- # filter by author and contract
- elif iden != None and author != None:
- if item['id'] == iden and list(item['change']['comments'].values())[0]['author'] == author:
- comment.append(item['change']['comments'])
- return comment
-
- # get updates for a contract that have to be accepted or are already accepted
- def retrieve_updates(self, iden, accepted=None):
-
- updates = {}
-
- # get all updates for a contract
- all_updates = self.get_updates(iden = iden, accepted = accepted)
-
- for item in all_updates:
- if item['type'] != 'accept' and item['updated'] != 'comments':
- updates[item['update id']] = item
- else:
- try:
- updates[item['update id']]['accepted'] = item['accept']
- except:
- pass
-
- if accepted == None:
- return updates
-
- return [updates[x] for x in list(updates.keys()) if updates[x]['accepted'] == accepted]
-
- def __str__(self):
- print(self.current_block)
- return ''
-
- def populate(self):
- # create contracts
- people = ['astrix', 'obelix']
- self.new_contract('some company', 'semmtech', 'two weeks', 'a sample project', 'project', 10000, people, 'astrix')
- people = ['samson', 'gert']
- self.new_contract('The organization', 'not semmtech', '31-12-2021', 'a real project', 'r project', 10000, people, 'samson')
- people = ['doctor bright', '05-12']
- self.new_contract('The foundation', 'scp-096', '31-12-2021', 'to contain 096', 'containment', 'at all costs', people, '05-2')
- # updates for contract 0
- self.update_contract(0, 'deadline', '1 month', 'obelix')
- self.accept_update(0, 0, True, 'astrix')
- self.update_contract(0, 'progress', '50%', 'astrix' ,'we done with 50 %')
- self.update_contract(0, 'discription', 'A project sample', 'obelix')
- self.update_contract(0, 'progress', '75%', 'astrix')
- self.add_comment(0, 'I like the progress', 'astrix')
- # updates for contract 1
- self.update_contract(1, 'accepted', True, 'gert')
- self.update_contract(1, 'Sign time', get_t(), 'gert')
- self.update_contract(1, 'name', 'actual project', 'samson')
- self.update_contract(1, 'price', 16969, 'gert')
- self.remove_item(1, 'comments')
- # updates for contract 2
- self.add_comment(2, 'needs to be terminated', 'doctor bright')
- self.add_comment(2, 'doctor bright is wrong', '05-12')
- self.add_comment(2, 'no im right 05-12 is defo wrong', 'doctor bright')
- self.update_contract(2, 'test term', 'works', '05-2')
- # # show current state of contract 0
- # self.current_contract_state(0)
- # pprint.pprint(self.state)
- # print('\n\n\n')
- # # show current state of contract 1
- # self.current_contract_state(1)
- # pprint.pprint(self.state)
- # print('\n\n\n')
- # show current state of contract 2
- self.current_contract_state(2)
- pprint.pprint(self.state)
-
- class Block():
-
- # init block
- def __init__(self):
- self.block = []
-
- # add new transactions
- def add(self, contract):
- self.block.append(contract)
-
- # get size of block
- def size(self):
- return len(self.block)
-
- def __str__(self):
- pprint.pprint(self.block)
- return ''
- # get date/time in readable format
- def get_t():
- return datetime.utcfromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
- # format a dictionary to be readable in a string
- def format_dict(d):
- # define string to return
- return_string = ''
- # loop over all key value pairs
- for k in list(d.keys()):
- # if value is a dict, call format dict again
- if type(d[k]) == dict:
- print('geweest')
- return_string += k + format_dict(d[k])
- # if list, join list with ', '
- elif type(d[k]) == list:
- return_string += k + ', '.join(d[k])
- # stings can just be added without further processing
- else:
- return_string += k + str(d[k])
- # and an enter after every value
- return_string += '\n'
- return return_string + '\n'
|