Skip to content

Commit

Permalink
CryptoKajmak blockchain web application
Browse files Browse the repository at this point in the history
  • Loading branch information
Majra Čaluk committed Mar 5, 2019
0 parents commit 2927fde
Show file tree
Hide file tree
Showing 171 changed files with 11,948 additions and 0 deletions.
75 changes: 75 additions & 0 deletions README.md
@@ -0,0 +1,75 @@
# CryptoKajmak Blockchain Web Application

Authors:
Dragoljuba Damjanovic
Majra Caluk

Demo of the CryptoKajmak application:
https://www.dropbox.com/s/h03vau6wyi7ss56/CryptoKajmakVideo.mp4?dl=0

Project documentation of the CryptoKajmak application:
https://docs.google.com/document/d/1AheNoImLaMBTQ-_f1_iUjt6NdZG6fuMiNfEM5KjHRYU/edit?usp=sharing

Explanation of the folder structure:

- crypto-kajmak: main folder
- kajmak-network: folder that contains all files necessary for starting the blochain network
- chaincode: folder that contains chaincode of the application
- client: folder that cointains front-end of the application
- folder: folder that contains Fabric Node.js client implementation. File helper.js is the point where the application interacts with the blockchain network
- user: folder that contains user definition in the external database
- server.js: file that containes server logic
- registerAdmin.sh: script that registers admin user
- startServer.sh: script that starts the server on the port 8000
- startKajmak.sh: script that starts the blockchain network

Front-end communicates with the server, server communicates with the helper.js file, helper.js file communicates with the chaincode, chaincode communicates with the ledger.

# Steps
## 1. Clone the repository
```
git clone https://github.com/iiMajRaii/crypto-kajmak.git
```
## 2. Create external database:
Go to [mLab](mlab.com/) and log in if you already have an account or sign up to create new one.
After that, open up your database dashboard.
Create new database by clicking on "Create New".
Select the free sandbox database and give it a name of your choice.
When the database is created, click on it. Then click on "Users" -> "Add database user".
Choose username and password.
You are able to see connection string that looks similar to this one:
```
mongodb://<dbuser>:<dbpassword>@ds243041.mlab.com:43041/cryptokajmakdb
```
Copy and paste that connection string into the database.js file.
Replace `<dbuser>` with the username and `<dbpassword>` with the password you chose in the previous step.

## 3. Run the application:
Navigate to crypto-kajmak folder using `cd` command:
```
cd crypto-kajmak
```
Start the blockchain network:
```
./startKajmak.sh
```
If getting error permission denied, run command:
```
chmod a+x startFabric.sh
```
Start the web server:
```
./startServer.sh
```
Open new terminal. Navigate again to the crypto-kajmak folder.
From the new terminal we will register admin user:
```
./registerAdmin.sh
```
Open the browser. Go to the page:
```
localhost:8000
```
Now you can start to use the application.

Login with username: adminuser and password: adminuser to be able to add new users into the network.
233 changes: 233 additions & 0 deletions chaincode/kajmak-app/kajmak-chaincode.go
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: Apache-2.0

/*
This code is based on code written by the Hyperledger Fabric community.
Original code can be found here: https://github.com/hyperledger/fabric-samples/blob/release/chaincode/fabcar/fabcar.go
*/

package main

/* Imports
* 4 utility libraries for handling bytes, reading and writing JSON,
formatting, and string manipulation
* 2 specific Hyperledger Fabric specific libraries for Smart Contracts
*/
import (
"bytes"
"encoding/json"
"fmt"
"strconv"

"github.com/hyperledger/fabric/core/chaincode/shim"
sc "github.com/hyperledger/fabric/protos/peer"
)

// Define the Smart Contract structure
type SmartContract struct {
}

//Kajmak struct definition
type Kajmak struct {
//id se ne upisuje
Name string `json:"name"`
Owner string `json:"owner"`
Animal string `json:"animal"`
Location string `json:"location"`
Quantity string `json:"quantity"`
ProductionDate string `json:"production_date"`
ExpirationDate string `json:"expiration_date"`

}

//Init method definition
func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response {
return shim.Success(nil)
}

//Invoke method definition
func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response {
function, args := APIstub.GetFunctionAndParameters()
if function == "initLedgerFirst" {
return s.initLedgerFirst(APIstub)
} else if function == "initLedgerSecond" {
return s.initLedgerSecond(APIstub)
} else if function == "recordKajmak" {
return s.recordKajmak(APIstub, args)
} else if function == "queryAllKajmak" {
return s.queryAllKajmak(APIstub)
} else if function == "changeKajmakOwner" {
return s.changeKajmakOwner(APIstub, args)
} else if function == "deleteKajmak" {
return s.deleteKajmak(APIstub, args)
} else if function == "changeKajmakQuantity" {
return s.changeKajmakQuantity(APIstub, args)
}
return shim.Error("Invalid Smart Contract function name.")
}

//initLedgerFirst method deifinition
func (s *SmartContract) initLedgerFirst(APIstub shim.ChaincodeStubInterface) sc.Response {
var kajmak = Kajmak{Name: "Kajmak1", Owner: "majra", Animal: "Sheep", Location: "Vlasic", Quantity: "340", ProductionDate: "05.10.2018. 10:55 am", ExpirationDate: "15.10.2019. 10:55 am"}

kajmakAsBytes, _ := json.Marshal(kajmak)
APIstub.PutState(strconv.Itoa(1), kajmakAsBytes)
fmt.Println("Added", kajmak)

return shim.Success(nil)
}


//initLedgerSecond method deifinition
func (s *SmartContract) initLedgerSecond(APIstub shim.ChaincodeStubInterface) sc.Response {
var kajmak = Kajmak{Name: "Kajmak2", Owner: "daca", Animal: "Cow", Location: "Trebinje", Quantity: "540", ProductionDate: "06.10.2018. 10:56 pm", ExpirationDate: "16.10.2019. 10:56 pm" }

kajmakAsBytes, _ := json.Marshal(kajmak)
APIstub.PutState(strconv.Itoa(2), kajmakAsBytes)
fmt.Println("Added", kajmak)

return shim.Success(nil)
}


//queryAllKajmak method definition
func (s *SmartContract) queryAllKajmak(APIstub shim.ChaincodeStubInterface) sc.Response {
startKey := "0"
endKey := "999"

resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()

// buffer is a JSON array containing QueryResults
var buffer bytes.Buffer
buffer.WriteString("[")

bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add comma before array members,suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")

buffer.WriteString(", \"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")

fmt.Printf("- queryAllKajmak:\n%s\n", buffer.String())

return shim.Success(buffer.Bytes())
}

//recordKajmak method definition
func (s *SmartContract) recordKajmak(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 8 {
return shim.Error("Incorrect number of arguments. Expecting 8")
}

var kajmak = Kajmak{ Name: args[1], Owner: args[2], Animal: args[3], Location: args[4], Quantity: args[5], ProductionDate: args[6], ExpirationDate: args[7] }
kajmakAsBytes, _ := json.Marshal(kajmak)
err := APIstub.PutState(args[0], kajmakAsBytes)
if err != nil {
return shim.Error(fmt.Sprintf("Failed to record tuna catch: %s", args[0]))
}
fmt.Printf("- recordKajmak:\n%s\n", kajmak)
return shim.Success(nil)
}

//changeKajmakOwner method definition
func (s *SmartContract) changeKajmakOwner(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}

kajmakAsBytes, _ := APIstub.GetState(args[0])
if kajmakAsBytes == nil {
return shim.Error("Could not locate kajmak")
}
kajmak := Kajmak{}

json.Unmarshal(kajmakAsBytes, &kajmak)
kajmak.Owner = args[1]

kajmakAsBytes, _ = json.Marshal(kajmak)
err := APIstub.PutState(args[0], kajmakAsBytes)
if err != nil {
return shim.Error(fmt.Sprintf("Failed to change kajmak owner: %s", args[0]))
}
fmt.Printf("-changeKajmakOwner:\n")
return shim.Success(nil)
}

//changeKajmakQuantity method definition
func (s *SmartContract) changeKajmakQuantity(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}

kajmakAsBytes, _ := APIstub.GetState(args[0])
if kajmakAsBytes == nil {
return shim.Error("Could not locate kajmak")
}
kajmak := Kajmak{}

json.Unmarshal(kajmakAsBytes, &kajmak)
kajmak.Quantity = args[1]

kajmakAsBytes, _ = json.Marshal(kajmak)
err := APIstub.PutState(args[0], kajmakAsBytes)
if err != nil {
return shim.Error(fmt.Sprintf("Failed to change kajmak quantity: %s", args[0]))
}
fmt.Printf("- changeKajmakQuantity:\n")
return shim.Success(nil)
}

//deleteKajmak method definition
func (s *SmartContract) deleteKajmak(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 8 {
return shim.Error("Incorrect number of arguments. Expecting 8")
}

err := APIstub.DelState(args[0])
if (err != nil) {
return shim.Error(fmt.Sprintf("Failed to delete kajmak: %s", args[0]))
}

eventPayload := "Kajmak with ID " + args[0] + " whose owner is " + args[2] + " was deleted because it has expired on date " + args[7]
payloadAsBytes := []byte(eventPayload)
eventErr := APIstub.SetEvent("deleteEvent",payloadAsBytes)
if (eventErr != nil) {
return shim.Error(fmt.Sprintf("Failed to emit event"))
}
fmt.Printf("- deleteKajmak:\n%s\n", args[0])
return shim.Success(nil);
}

/*
/*
* main function *
calls the Start function
The main function starts the chaincode in the container during instantiation.
*/
func main() {

// Create a new Smart Contract
err := shim.Start(new(SmartContract))
if err != nil {
fmt.Printf("Error creating new Smart Contract: %s", err)
}
}
82 changes: 82 additions & 0 deletions client/addUser.css
@@ -0,0 +1,82 @@
.container {
border: solid white 1px;
height: 90%;
overflow: auto;
background-image: url('https://picjumbo.com/wp-content/uploads/white-marble-stone-background-texture-pattern_free_stock_photos_picjumbo_marble_free_stock_photos_picjumbo_com-2210x1473.jpg');
/*background-image: url('https://cdn.hipwallpaper.com/i/87/11/COeNh7.png'); */
}

.main {
border: solid white 1px;
width:100%;
padding:100px 20px;
height: 100%;
text-align: center;
}

.main h2 {
text-transform: uppercase;
}

.form {
border: solid #bf9b30 3px;
background-color: black;
width: 40%;
font-size: 20px;
color: #bf9b30;
padding-top:5px;
margin: 0 auto;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}

input,select {
font-size: 20px;
width: 90%;
margin-top: 10px;
margin-bottom: 3px;
padding: 2px;
color: black;
background-color: #eaeaea;
}

.addUser, .logout {
background: #bf9b30;
border: none;
height: 50px;
text-transform: uppercase;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
margin-bottom: 10px;
}

.addUser:hover, .logout:hover {
color: silver;
font-weight: bold;
}

.logout {
position: absolute;
top: 12%;
right: 10px;
}

.footer {
background-color: black;
height: 10%;
}

.footer h3 {
color: #aadb12;
text-align: center;
}

span p {
color: red;
font-size: 15px;
margin: 0;
padding: 0;

}

[ng-cloak] {
display: none !important;
}

0 comments on commit 2927fde

Please sign in to comment.