2
0

linked_data.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. import time
  2. import pprint
  3. from datetime import datetime
  4. class Chain():
  5. def __init__(self):
  6. # initialize the mock blockchain
  7. self.blockchain = []
  8. self.current_block = Block()
  9. # add old block to chain and create new block
  10. def new_block(self):
  11. self.blockchain.append(self.current_block)
  12. self.current_block = Block()
  13. pass
  14. # create new contract
  15. def new_contract(self,client, contractor, deadline, discription, name, price, people, initiator):
  16. n_contracts = 0
  17. for block in self.blockchain + [self.current_block]:
  18. for item in block.block:
  19. if item['type'] == 'init':
  20. n_contracts += 1
  21. # set discriptors of contract
  22. contract = {'id':n_contracts,
  23. 'type':'init',
  24. 'date of initiation':get_t(),
  25. 'initiated by': initiator,
  26. 'data': {'client':client,
  27. 'contractor':contractor,
  28. 'discription':discription,
  29. 'name':name,
  30. 'people': people},
  31. 'terms' : {'deadline': deadline,
  32. 'accepted': False,
  33. 'progress': '0%',
  34. 'price':price,
  35. 'Sign time': 'not yet signed',
  36. 'comments':{}
  37. }
  38. }
  39. # add as transaction
  40. self.current_block.add(contract)
  41. # If block to big, get new
  42. if self.current_block.size() > 10:
  43. self.new_block()
  44. # add updates to the contract
  45. def update_contract(self, iden, attr, value, by, comment=None):
  46. # check if transaction adds or modifies
  47. self.current_contract_state(iden)
  48. if attr in self.state['data'] or attr in self.state['terms']:
  49. t = 'modify'
  50. else: t = 'update'
  51. # add new or updated info to block
  52. update = {'id':iden,
  53. 'update id':len(self.get_updates(iden)),
  54. 'updated':attr,
  55. 'type':t,
  56. 'last update':get_t(),
  57. 'updated by':by,
  58. 'accepted': False,
  59. 'change':{attr:value}}
  60. # check if comment is passed and add it if necassary
  61. if comment:
  62. update['comment'] = comment
  63. # add transaction
  64. self.current_block.add(update)
  65. # check if new block is needed
  66. if self.current_block.size() > 10:
  67. self.new_block()
  68. # accept updates
  69. def accept_update(self, iden, update_id, awnser, by, comment=None):
  70. update = {
  71. 'id':iden,
  72. 'update id':update_id,
  73. 'accept':awnser,
  74. 'type':'accept',
  75. 'last update':get_t(),
  76. 'accepted by': by
  77. }
  78. if comment:
  79. update['comment'] = comment
  80. self.current_block.add(update)
  81. # check if new block is needed
  82. if self.current_block.size() > 10:
  83. self.new_block()
  84. # get current state of the contract
  85. def current_contract_state(self, iden):
  86. # set up contract state
  87. self.state = {'id':iden,
  88. 'data':{},
  89. 'terms':{}
  90. }
  91. b = []
  92. # loop over all blocks in the chain
  93. for block in self.blockchain:
  94. b += block.block
  95. # retreive all the data
  96. transactions = b + self.current_block.block
  97. # save not yet approved updates
  98. updates = {}
  99. # loop over all transaction in block
  100. for item in transactions:
  101. # save data about our project
  102. if item['id'] == iden:
  103. # set state to inital contract state
  104. if item['type'] == 'init':
  105. self.state = item
  106. continue
  107. # if update is not accept update, save it to updates dict
  108. if item['type'] != 'accept':
  109. # comments are always accepted
  110. if item['updated'] != 'comments':
  111. updates[item['update id']] = item
  112. continue
  113. # if accepted is true, retrieve update form dict and add to contract state
  114. elif item['accept'] == True:
  115. item = updates[item['update id']]
  116. # set attr to whatever has been updated
  117. attr = item['updated']
  118. # check if the update was removal
  119. if item['type'] == 'remove':
  120. # delete item in the right part of the dict
  121. try:
  122. if attr in self.state['data']:
  123. del self.state['data'][attr]
  124. else:
  125. del self.state['terms'][attr]
  126. except:
  127. pass
  128. if item['type'] == 'update':
  129. self.state['terms'][attr] = item['change'][attr]
  130. # check if updated attr is data or terms
  131. elif attr in self.state['data']:
  132. self.state['data'][attr] = item['change'][attr]
  133. elif attr in self.state['terms']:
  134. # special case for comments
  135. if attr == 'comments' and item['type'] not in ['remove', 'init']:
  136. k = list(item['change'][attr].keys())[0]
  137. self.state['terms'][attr][k] = item['change'][attr][k]
  138. # case for normal updates
  139. else:
  140. self.state['terms'][attr] = item['change'][attr]
  141. # special cases for last update and date of initiation
  142. elif 'last update' in item:
  143. self.state['last update'] = item['last update']
  144. # get updates based on contract, atribute updated or accept state
  145. def get_updates(self, iden=None, attr=None, accepted=None):
  146. updates = []
  147. # get all blocks and loop over transactions
  148. for block in self.blockchain + [self.current_block]:
  149. for item in block.block:
  150. # if attr is '' get updates for all attributes
  151. if attr == None:
  152. # if iden is None, get updates for all contracts
  153. # updates for all contracts and attrs
  154. if iden == None:
  155. if item['type'] != 'init':
  156. updates.append(item)
  157. # updates for specific contracts from all attr
  158. else:
  159. if item['type'] != 'init' and item['id'] == iden:
  160. updates.append(item)
  161. else:
  162. # updates for specific attrs from all contract
  163. if iden == None:
  164. if item['type'] != 'init' and item['updated'] == attr:
  165. updates.append(item)
  166. # updates for specific contract and specific attr
  167. else:
  168. if item['type'] != 'init' and item['updated'] == attr and item['id'] == iden:
  169. updates.append(item)
  170. return updates
  171. # add transaction to remove items
  172. def remove_item(self, iden, attr):
  173. # add transaction to remove item
  174. self.current_block.add({'id':iden,
  175. 'updated':attr ,
  176. 'type':'remove',
  177. 'last update':get_t(),
  178. 'accept':False,
  179. 'update id':len(self.get_updates(iden))})
  180. if self.current_block.size() > 10:
  181. self.new_block()
  182. # add comments to
  183. def add_comment(self, iden, body, author):
  184. # get all updates for comments
  185. comment_updates = []
  186. for block in self.blockchain + [self.current_block]:
  187. for item in block.block:
  188. if 'updated' in item:
  189. if item['updated'] == 'comments' and item['id'] == iden:
  190. comment_updates.append(item)
  191. # create transaction
  192. to_add = {'id':iden,
  193. 'updated':'comments',
  194. 'accept':True,
  195. 'type':'modify',
  196. 'last update':get_t(),
  197. 'change':{'comments':{len(comment_updates):{'author':author,
  198. 'body': body,
  199. 'time': get_t(),
  200. 'contract':iden}}}}
  201. self.current_block.add(to_add)
  202. if self.current_block.size() > 10:
  203. self.new_block()
  204. # retrieve comments based on author and contract
  205. def retrieve_comments(self, iden=None, author = None):
  206. comment = []
  207. # check every block in the chain
  208. for block in self.blockchain + [self.current_block]:
  209. for item in block.block:
  210. # if transaction is of type init, skip it
  211. if item['type'] == 'init' or item['type'] == 'accept':
  212. continue
  213. # check if the update is a comment
  214. if item['updated'] == 'comments':
  215. #filters for contract and author
  216. # no contract or author filter
  217. if iden == None and author == None:
  218. comment.append(item['change']['comments'])
  219. # filter by contract
  220. elif iden != None and author == None:
  221. if item['id'] == iden:
  222. comment.append(item['change']['comments'])
  223. # filter by author
  224. elif iden == None and author != None:
  225. if list(item['change']['comments'].values())[0]['author'] == author:
  226. comment.append(item['terms']['comments'])
  227. # filter by author and contract
  228. elif iden != None and author != None:
  229. if item['id'] == iden and list(item['change']['comments'].values())[0]['author'] == author:
  230. comment.append(item['change']['comments'])
  231. return comment
  232. # get updates for a contract that have to be accepted or are already accepted
  233. def retrieve_updates(self, iden, accepted=None):
  234. updates = {}
  235. # get all updates for a contract
  236. all_updates = self.get_updates(iden = iden, accepted = accepted)
  237. for item in all_updates:
  238. if item['type'] != 'accept' and item['updated'] != 'comments':
  239. updates[item['update id']] = item
  240. else:
  241. try:
  242. updates[item['update id']]['accepted'] = item['accept']
  243. except:
  244. pass
  245. if accepted == None:
  246. return updates
  247. return [updates[x] for x in list(updates.keys()) if updates[x]['accepted'] == accepted]
  248. def __str__(self):
  249. print(self.current_block)
  250. return ''
  251. def populate(self):
  252. # create contracts
  253. people = ['astrix', 'obelix']
  254. self.new_contract('some company', 'semmtech', 'two weeks', 'a sample project', 'project', 10000, people, 'astrix')
  255. people = ['samson', 'gert']
  256. self.new_contract('The organization', 'not semmtech', '31-12-2021', 'a real project', 'r project', 10000, people, 'samson')
  257. people = ['doctor bright', '05-12']
  258. self.new_contract('The foundation', 'scp-096', '31-12-2021', 'to contain 096', 'containment', 'at all costs', people, '05-2')
  259. # updates for contract 0
  260. self.update_contract(0, 'deadline', '1 month', 'obelix')
  261. self.accept_update(0, 0, True, 'astrix')
  262. self.update_contract(0, 'progress', '50%', 'astrix' ,'we done with 50 %')
  263. self.update_contract(0, 'discription', 'A project sample', 'obelix')
  264. self.update_contract(0, 'progress', '75%', 'astrix')
  265. self.add_comment(0, 'I like the progress', 'astrix')
  266. # updates for contract 1
  267. self.update_contract(1, 'accepted', True, 'gert')
  268. self.update_contract(1, 'Sign time', get_t(), 'gert')
  269. self.update_contract(1, 'name', 'actual project', 'samson')
  270. self.update_contract(1, 'price', 16969, 'gert')
  271. self.remove_item(1, 'comments')
  272. # updates for contract 2
  273. self.add_comment(2, 'needs to be terminated', 'doctor bright')
  274. self.add_comment(2, 'doctor bright is wrong', '05-12')
  275. self.add_comment(2, 'no im right 05-12 is defo wrong', 'doctor bright')
  276. self.update_contract(2, 'test term', 'works', '05-2')
  277. # # show current state of contract 0
  278. # self.current_contract_state(0)
  279. # pprint.pprint(self.state)
  280. # print('\n\n\n')
  281. # # show current state of contract 1
  282. # self.current_contract_state(1)
  283. # pprint.pprint(self.state)
  284. # print('\n\n\n')
  285. # show current state of contract 2
  286. self.current_contract_state(2)
  287. pprint.pprint(self.state)
  288. class Block():
  289. # init block
  290. def __init__(self):
  291. self.block = []
  292. # add new transactions
  293. def add(self, contract):
  294. self.block.append(contract)
  295. # get size of block
  296. def size(self):
  297. return len(self.block)
  298. def __str__(self):
  299. pprint.pprint(self.block)
  300. return ''
  301. # get date/time in readable format
  302. def get_t():
  303. return datetime.utcfromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
  304. # format a dictionary to be readable in a string
  305. def format_dict(d):
  306. # define string to return
  307. return_string = ''
  308. # loop over all key value pairs
  309. for k in list(d.keys()):
  310. # if value is a dict, call format dict again
  311. if type(d[k]) == dict:
  312. print('geweest')
  313. return_string += k + format_dict(d[k])
  314. # if list, join list with ', '
  315. elif type(d[k]) == list:
  316. return_string += k + ', '.join(d[k])
  317. # stings can just be added without further processing
  318. else:
  319. return_string += k + str(d[k])
  320. # and an enter after every value
  321. return_string += '\n'
  322. return return_string + '\n'