Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Mok committed Jul 8, 2018
0 parents commit 69174e9
Show file tree
Hide file tree
Showing 24 changed files with 1,019 additions and 0 deletions.
19 changes: 19 additions & 0 deletions admin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>Administrator</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'/>
<link rel="shortcut icon" type="image/png" href="images/certificate.ico"/>
</head>
<body class="container">
<div class="page-header">
<h1>Welcome, Administrator!</h1>
</div>
<a href="student-list.html" class="btn btn-success form-control" style="margin: 1em 0">Student Listing</a>
<a href="issuer-list.html" class="btn btn-warning form-control" style="margin: 1em 0">Issuer Listing</a>
<a href="index.html" class="btn">Back</a>
</body>
<script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
</html>
4 changes: 4 additions & 0 deletions bs-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"port": 80,
"open": false
}
38 changes: 38 additions & 0 deletions certificate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title>Create Certificate</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'/>
<link rel="shortcut icon" type="image/png" href="images/certificate.ico"/>
</head>
<body class="container">
<div class="page-header">
<h1>Create Certificate</h1>
</div>
<form>
<div class="alert alert-success" role="alert" style="display: none">
Certificate record created.
</div>
<div class="form-group">
<input type="text" class="form-control" id="course-title" placeholder="Course or programme title" required="required"/>
</div>
<div class="form-group">
<input type="text" class="form-control" id="address" placeholder="Student account address" required="required" pattern=".{42}" title="Address should have 42 characters"/>
</div>
<div class="form-group">
<input type="text" class="form-control" id="completion-date" onfocus="this.type='date'" onblur="this.type='text'" placeholder="Completion date" required="required"/>
</div>
<div class="form-group">
<input type="text" class="form-control" id="expiry-date" onfocus="this.type='date'" onblur="this.type='text'" placeholder="Expiry date" />
</div>
<div class="alert alert-danger" role="alert" style="display: none">
</div>
<input type="submit" class="btn btn-primary" value="Create Certificate"/>
<a href="issuer-certificates.html" class="btn">Back</a>
</form>
</body>
<script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="js/certificate.js"></script>
</html>
238 changes: 238 additions & 0 deletions contracts/Master.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
pragma solidity ^0.4.23;

contract Master {

struct Certificate {
address student;
address issuer;
string courseTitle;
string completionDate;
string expiryDate;
}

struct Student {
string name;
}

struct Issuer {
string issuerName;
string logoUrl;
string issuerAddress;
}

mapping (address => Student) private students;
address[] private studentAddresses;

mapping (address => Issuer) private issuers;
address[] private issuerAddresses;

Certificate[] private certificates;

address private adminOwner;

constructor() public {
adminOwner = msg.sender;
}

// create new student (admin)
function createStudent(address _address, string _name) public {

// Check current user is admin
require(adminOwner == msg.sender);

// Check if account already exists
validateAddress(_address);

// Add a new student contract to students map
students[_address] = Student({
name: _name
});

// Add the address to studentAddresses array
studentAddresses.push(_address);
}

function listStudentAddresses() public view returns (address[]) {

return studentAddresses;
}

function listIssuerAddresses() public view returns (address[]) {

return issuerAddresses;
}

function getStudentName(address _address) public view returns (string) {

for (uint count = 0; count < studentAddresses.length; count++) {
if (studentAddresses[count] == _address) {
return students[_address].name;
}
}

revert();
}

function getIssuerName(address _address) public view returns (string) {

for (uint count = 0; count < issuerAddresses.length; count++) {
if (issuerAddresses[count] == _address) {
return issuers[_address].issuerName;
}
}

revert();
}

function getIssuerDetails(address _address) public view returns (string, string, string) {

for (uint count = 0; count < issuerAddresses.length; count++) {
if (issuerAddresses[count] == _address) {
Issuer storage issuer = issuers[_address];
return (issuer.issuerName, issuer.logoUrl, issuer.issuerAddress);
}
}

revert();
}

// create new issuer (admin)
function createIssuer(address _address, string _name, string _issuerAddress, string _logoUrl) public {

// Check current user is admin
require(adminOwner == msg.sender);

// Check if account already exists
validateAddress(_address);

// Add a new issuer contract to issuers map
issuers[_address] = Issuer({
issuerName: _name,
issuerAddress: _issuerAddress,
logoUrl: _logoUrl
});

// Add the address to issuerAddresses array
issuerAddresses.push(_address);
}

function validateAddress(address _address) view private {

// Check if account already exists
for (uint count = 0; count < studentAddresses.length; count++) {
if (studentAddresses[count] == _address) {
revert();
}
}

for (count = 0; count < issuerAddresses.length; count++) {
if (issuerAddresses[count] == _address) {
revert();
}
}

if (_address == adminOwner) {
revert();
}
}

// create new certificate (issuer)
function createCertificate(address student, string courseTitle, string completionDate, string expiryDate) public {

for (uint studentCount = 0; studentCount < studentAddresses.length; studentCount++) {
if (studentAddresses[studentCount] == student) {
for (uint issuerCount = 0; issuerCount < issuerAddresses.length; issuerCount++) {
if (issuerAddresses[issuerCount] == msg.sender) {
certificates.push(Certificate({
student: student,
issuer: msg.sender,
courseTitle: courseTitle,
completionDate: completionDate,
expiryDate: expiryDate
}));
return;
}
}
}
}

revert();
}

// Verify a certificate
function verifyCertificate(address student, address issuer, string courseTitle) public view returns (uint) {

for (uint count = 0; count < certificates.length; count++) {
Certificate storage certificate = certificates[count];
if (certificate.student == student && certificate.issuer == issuer && equal(certificate.courseTitle, courseTitle)) {
return count + 1;
}
}

// validate expiry date

return 0;
}

// Student to query his/her own certificates
function getStudentCertificates() public view returns (uint[]) {

uint[] memory studentCertificates = new uint[](certificates.length);
uint index = 0;
for (uint count = 0; count < certificates.length; count++) {
if (certificates[count].student == msg.sender) {
studentCertificates[index++] = count;
}
}
return studentCertificates;
}

// Issuer to query issued certificates
function getIssuerCertificates() public view returns (uint[]) {

uint[] memory issuedCertificates = new uint[](certificates.length);
uint index = 0;
for (uint count = 0; count < certificates.length; count++) {
if (certificates[count].issuer == msg.sender) {
issuedCertificates[index++] = count;
}
}
return issuedCertificates;
}

function getCertificateDetails(uint index) public view returns (string, string, string, string, string) {

require(index < certificates.length);
Certificate storage certificate = certificates[index];
return (issuers[certificate.issuer].issuerName, students[certificate.student].name, certificate.courseTitle, certificate.completionDate, certificate.expiryDate);
}

function compare(string _a, string _b) private pure returns (int) {

bytes memory a = bytes(_a);
bytes memory b = bytes(_b);
uint minLength = a.length;
if (b.length < minLength) minLength = b.length;
for (uint i = 0; i < minLength; i ++)
if (a[i] < b[i])
return -1;
else if (a[i] > b[i])
return 1;
if (a.length < b.length)
return -1;
else if (a.length > b.length)
return 1;
else
return 0;
}

function equal(string _a, string _b) private pure returns (bool) {

return compare(_a, _b) == 0;
}

// edit new student (admin / student)
// edit new issuer (admin / issuer)
// revoke new certificate (issuer)

}
33 changes: 33 additions & 0 deletions deploy-contract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
console.log('Deploy started on ' + new Date());
console.log('Loading libraries');

var fs = require('fs');
var Web3 = require('web3');
var solc = require('solc');
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

console.log('Compiling Solidity contracts');

var compiled = solc.compile(fs.readFileSync('contracts/Master.sol').toString());
var abiDefinition = compiled.contracts[':Master'].interface;
console.log('ABI Definition: ' + abiDefinition);

var byteCode = compiled.contracts[':Master'].bytecode;
var estimatedGas = web3.eth.estimateGas({data: byteCode});
console.log('Deploying contracts using estimated gas ' + estimatedGas);

var contract = web3.eth.contract(JSON.parse(abiDefinition)).new(null, {data: byteCode, from: web3.eth.accounts[0], gas: estimatedGas});

new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {

console.log('Contract address: ' + contract.address);
console.log('Writing dummy data');
console.log('Creating issuer');
contract.createIssuer(web3.eth.accounts[1], 'HKU', 'Pokfulam Road, HK', 'http://avuou.hku.hk/guestpage/HKUbw2.gif', {from: web3.eth.accounts[0], gas: contract.createIssuer.estimateGas(web3.eth.accounts[1], 'HKU', 'Pokfulam Road, HK', 'http://avuou.hku.hk/guestpage/HKUbw2.gif')});
console.log('Creating student');
contract.createStudent(web3.eth.accounts[2], 'Simon Chan', {from: web3.eth.accounts[0], gas: contract.createStudent.estimateGas(web3.eth.accounts[2], 'Simon Chan')});
console.log('Creating certificate');
web3.eth.defaultAccount = web3.eth.accounts[1];
contract.createCertificate(web3.eth.accounts[2], 'Introduction to Blockchain', '2018-07-01', '2028-08-31', {from: web3.eth.accounts[1], gas: contract.createCertificate.estimateGas(web3.eth.accounts[2], 'Introduction to Blockchain', '2018-07-01', '2028-08-31')});
console.log('Deploy complete at ' + new Date());
});
Binary file added images/cert-template.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/certificate.ico
Binary file not shown.
20 changes: 20 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Certificate Blockchain Apps</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'/>
<link rel="shortcut icon" type="image/png" href="images/certificate.ico"/>
</head>
<body class="container">
<div class="page-header">
<h1>Welcome to Certificate Blockchain Apps</h1>
</div>
<a href="search.html" class="btn btn-primary form-control" style="margin: 1em 0">Verify Certificate</a>
<a href="student-certificates.html" class="btn btn-success form-control" style="margin: 1em 0">I am a student</a>
<a href="issuer-certificates.html" class="btn btn-warning form-control" style="margin: 1em 0">I am an issuer</a>
<a href="admin.html" class="btn btn-danger form-control" style="margin: 1em 0">I am the administrator</a>
</body>
<script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
</html>
Loading

0 comments on commit 69174e9

Please sign in to comment.