Bläddra i källkod

Linked data part is now in a python file, started working on the gui

justtheboss97 4 år sedan
förälder
incheckning
24592e3088
2 ändrade filer med 490 tillägg och 0 borttagningar
  1. 78 0
      gui.py
  2. 412 0
      linked_data.py

+ 78 - 0
gui.py

@@ -0,0 +1,78 @@
+from tkinter import *
+from linked_data import Chain, format_dict
+import pprint
+
+chain = Chain()
+chain.populate()
+
+root = Tk()
+root.title('dsp blockchain')
+
+view = Entry(root, width=35, borderwidth=5)
+view.grid(row=0, column=1, columnspan=3, padx=10, pady=10)
+
+
+def myClick():
+    print(view.get())
+    chain.current_contract_state(int(view.get()))
+    pprint.pprint(chain.state)
+
+def add_contract():
+
+    # add contract to the blockchain
+    def add():
+        chain.new_contract(client.get(), contractor.get(), deadline.get(), description.get(), name.get(), int(price.get()), people.get().split(','), initiator.get())
+
+        # destroy add contract window, and print conformation
+        newWindow.destroy()
+        print('contract added')
+
+    # make new window for adding the information for the contract
+    newWindow = Toplevel(root)
+    newWindow.title('Add contract')
+
+    # create all text boxes
+    Label(newWindow, text='The client: ').grid(row=0, column=0)
+    client =  Entry(newWindow, width=35, borderwidth=5)
+    client.grid(row=0, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='The contractor: ').grid(row=1, column=0)
+    contractor =  Entry(newWindow, width=35, borderwidth=5)
+    contractor.grid(row=1, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='Deadline: ').grid(row=2, column=0)
+    deadline =  Entry(newWindow, width=35, borderwidth=5)
+    deadline.grid(row=2, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='Description: ').grid(row=3, column=0)
+    description =  Entry(newWindow, width=35, borderwidth=5)
+    description.grid(row=3, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='Project name: ').grid(row=4, column=0)
+    name =  Entry(newWindow, width=35, borderwidth=5)
+    name.grid(row=4, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='Price: ').grid(row=5, column=0)
+    price =  Entry(newWindow, width=35, borderwidth=5)
+    price.grid(row=5, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='People involved: ').grid(row=6, column=0)
+    people =  Entry(newWindow, width=35, borderwidth=5)
+    people.grid(row=6, column=1, columnspan=3, padx=10, pady=10)
+
+    Label(newWindow, text='Initiator').grid(row=7, column=0)
+    initiator =  Entry(newWindow, width=35, borderwidth=5)
+    initiator.grid(row=7, column=1, columnspan=3, padx=10, pady=10)
+
+    # create the add contract button
+    add_c = Button(newWindow, text = "Add contract", command=add)
+    add_c.grid(row=8, column=0)
+    
+
+myButton = Button(root, text="View contract", command=myClick)
+myButton.grid(row=0, column=0)
+
+myButton = Button(root, text="New contract", command=add_contract)
+myButton.grid(row=1, column=0)
+
+root.mainloop()

+ 412 - 0
linked_data.py

@@ -0,0 +1,412 @@
+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'
+
+