Skip to content
Permalink
Browse files

Explorer rebuilt for Flask; initial Creator tool

  • Loading branch information
kdmukai committed Jul 20, 2019
1 parent 3c305c1 commit 46cb81d7dfc6e0df721e028b9a03f9257862f556
Showing with 1,077 additions and 248 deletions.
  1. +4 −0 .gitignore
  2. +3 −3 README.md
  3. +58 −0 creator/README.md
  4. 0 {explorer → creator}/babel.rc
  5. +1 −6 {explorer → creator}/package-lock.json
  6. +0 −1 {explorer → creator}/package.json
  7. +189 −0 creator/src/index.js
  8. +87 −0 creator/src/pageoverlay.js
  9. +231 −0 creator/src/static/index.html
  10. +6 −0 creator/src/static/local_settings--example.js
  11. +1 −1 {explorer → creator}/webpack.config.js
  12. +70 −12 explorer/README.md
  13. +94 −0 explorer/explorer/explorer.py
  14. +4 −0 explorer/explorer/run.sh
  15. +18 −4 explorer/{src/static/css → explorer/static}/explorer.css
  16. BIN explorer/explorer/static/img/favicon/android-chrome-192x192.png
  17. BIN explorer/explorer/static/img/favicon/android-chrome-384x384.png
  18. BIN explorer/explorer/static/img/favicon/apple-touch-icon.png
  19. +9 −0 explorer/explorer/static/img/favicon/browserconfig.xml
  20. BIN explorer/explorer/static/img/favicon/favicon-16x16.png
  21. BIN explorer/explorer/static/img/favicon/favicon-32x32.png
  22. BIN explorer/explorer/static/img/favicon/favicon.ico
  23. BIN explorer/explorer/static/img/favicon/mstile-150x150.png
  24. +19 −0 explorer/explorer/static/img/favicon/site.webmanifest
  25. BIN explorer/explorer/static/img/waxbadges_logo_350x72.png
  26. +32 −0 explorer/explorer/templates/_base.html
  27. +67 −0 explorer/explorer/templates/ach.html
  28. +106 −0 explorer/explorer/templates/ecosys.html
  29. +35 −0 explorer/explorer/templates/index.html
  30. +21 −0 explorer/requirements.txt
  31. +0 −117 explorer/src/index.js
  32. +0 −99 explorer/src/static/index.html
  33. +22 −5 waxbadges.cpp
@@ -7,6 +7,8 @@
*.o
*.obj
*.abi
__pycache__
*.pyc

# Precompiled Headers
*.gch
@@ -39,3 +41,5 @@ node_modules/


wallet_password.txt
local_settings.js
zappa_settings.json
@@ -321,11 +321,11 @@ cleos -u https://chain.wax.io set contract waxbadgesftw /path/to/contracts/waxba
cleos -u https://chain.wax.io push action waxbadgesftw wipetables '[]' -p waxbadgesftw@active
cleos -u https://chain.wax.io push action waxbadgesftw addecosys '["waxbadgesftw", "WAXBadges Genesis Campaign", "https://waxbadges.com", "assets.waxbadges.com/ecosys/genesis", "waxbadges_logo.png"]' -p waxbadgesftw@active
cleos -u https://chain.wax.io push action waxbadgesftw addecosys '["waxbadgesftw", "WAXBadges Genesis Campaign", "https://waxbadges.com", "explorer.waxbadges.com/assets", "waxbadges_logo.png"]' -p waxbadgesftw@active
cleos -u https://chain.wax.io push action waxbadgesftw addcat '["waxbadgesftw", "0", "twitter"]' -p waxbadgesftw@active
cleos -u https://chain.wax.io push action waxbadgesftw addach '["waxbadgesftw", "0", "0", "First", "First achievement ever. First 50 to follow @WAXBadges.", "first.png", "50"]' -p waxbadgesftw@active
cleos -u https://chain.wax.io push action waxbadgesftw addach '["waxbadgesftw", "0", "0", "First", "First achievement ever. First 50 to follow @WAXBadges.", "ach_hand.png", "50"]' -p waxbadgesftw@active
```


@@ -347,4 +347,4 @@ cleos -u https://chain.wax.io push action waxbadgesftw addach '["waxbadgesftw",

* Add support for a points system for each `Achievement`, point totals for `User`s?

*
* Shard Ecosystems User table for huge ecosystems?
@@ -0,0 +1,58 @@
# WAXBadges Achievements CREATOR
_A tool for game studios (and anyone else) to create their own WAXBadges achievement ecosystem_


This creator is built as static html/JS that you run locally to create and management your WAXBadges achievements. By running locally we can make some safe-ish security compromises that greatly enhance your workflow speed (i.e. hard-coding your private key for instant transaction signing; normally a MEGA no-no!!).


### Getting started:
* Set up your WAX blockchain account
* Create a free WAX All Access account ([account.wax.io](https://account.wax.io))
* On the Scatter step, opt to generate new keys that are stored in Scatter. We'll need direct access to your private key.
* Fund it with some WAX tokens
* Buy from an exchange and transfer to your WAX account (details are beyond the scope of this doc)
* Purchase some RAM
* Spend WAX to buy RAM in Scatter (how much? A couple hundred kB is fine for starters)
* Download the static html/js files
* Optionally build it from source yourself
* Customize the `local_settings.js` file
* Enter your account's private key
* Enter the associated WAX account name (e.g. abc12.waa)
* Double click the `index.html` to run it as a locally-hosted webpage

Now that you've hard-coded your private key you must keep these files secure on your local machine. Never upload or host these files on the web! The creator looks and acts like a normal website, but treat it as a tool that you install on your local machine. If anyone else on your team needs access, they'll have to download and customize their own local copy.


### Wait, isn't this risky?
I mean, kinda. We're greatly reducing risk by only running this customized javascript on your local computer. But anytime you're directly handling a private key you are absolutely in a danger zone.

A future enhancement will enable an _authorize-in-Scatter_ option. This will keep your private key in Scatter (or, even better, in a hardware wallet that's connected to Scatter). But as a trade-off you'll have to manually approve every transaction. If you're adding 30 achievements to your new ecosystem it's going to be a pain, though hopefully we'll be able to batch transactions to reduce the number of approvals.


### Bonus security
Add a hardware wallet like a Ledger to Scatter and change your WAX account's "owner" key to the hardware wallet key. The steps above risk compromising your WAX account's "active" key but if you retain tight control of the "owner" key, you can always generate a new "active" key for your account.



## Building from source
Grab the `npm` modules:
```
npm init
npm install
```

Build for dev:
```
npm run dev
```

Run locally with Hot Module Replacement:
```
webpack-dev-server --hot --host 0.0.0.0
```

Build minified production payload:
```
npm run build
```

File renamed without changes.

Some generated files are not rendered by default. Learn more.

@@ -11,7 +11,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"bootstrap": "^4.3.1",
"eosjs": "^20.0.0",
"jquery": "^3.4.1"
},
@@ -0,0 +1,189 @@
let $ = require("jquery");

import { Api, JsonRpc, RpcError } from 'eosjs';
import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig';

let PageOverlay = require("./pageoverlay");
var pageoverlay;


var rpc = new JsonRpc('https://chain.wax.io');
var api;
var signatureProvider;


let CONTRACT = 'waxbadgesftw';


async function renderIndex() {
console.log(ACCOUNT_NAME);

pageoverlay.initPageOverlay($("#add_ecosys_container"));
$("#add_ecosys_button").click(function() {
console.log("click");
pageoverlay.showPageOverlay($("#add_ecosys_container"));
});

$("#add_ecosys_submit_button").click(function() {
let name = $("#add_ecosys_name").val();
let description = $("#add_ecosys_description").val();
let website = $("#add_ecosys_website").val();
let assetbaseurl = $("#add_ecosys_assetbaseurl").val();
let logoassetname = $("#add_ecosys_logoassetname").val();

if (name == "") {
alert("ecosystem name is required!");
return;
}
if (website != "" && (!website.startsWith('http://') && !website.startsWith('https://'))) {
alert("website should begin with 'http' or 'https'");
return;
}
if (website == "" && assetbaseurl != "") {
alert("website is required if assetbaseurl is specified!");
return;
}

(async () => {
const result = await api.transact(
{
actions: [{
account: CONTRACT,
name: 'addecosys',
authorization: [{
actor: ACCOUNT_NAME,
permission: 'active',
}],
data: {
ecosystem_owner: ACCOUNT_NAME,
ecosystem_name: name,
description: description,
website: website,
assetbaseurl: assetbaseurl,
logoassetname: logoassetname
},
}]
},
{
blocksBehind: 3,
expireSeconds: 30,
}
);

console.dir(result);
})();

});


const resp = await rpc.get_table_rows({
json: true, // Get the response as json
code: CONTRACT, // Contract that we target
scope: CONTRACT, // Account that owns the data
table: 'ecosystems', // Table name
index_position: 2, // Table secondary key index
key_type: 'i64', // Secondary index type
lower_bound: ACCOUNT_NAME, // Table secondary key value
upper_bound: ACCOUNT_NAME, // Table secondary key value
limit: 10, // Maximum number of rows that we want to get
});

console.log(resp.rows);

for(var i=0; i < resp.rows.length; i++) {
var ecosystem = resp.rows[i];
$("#page_index").find(".ecosystems_list").append("<div><a href='/ecosys/" + ecosystem.key + "'>" + ecosystem.name + "</a></div>");
}

$("#page_index").show();
}



// ecosys.html
async function renderEcosys(key) {
const resp = await rpc.get_table_rows({
json: true, // Get the response as json
code: CONTRACT, // Contract that we target
scope: CONTRACT, // Account that owns the data
table: 'ecosystems', // Table name
lower_bound: key,
upper_bound: key,
limit: 1, // Maximum number of rows that we want to get
});

console.log(resp.rows);

if (resp.rows.length == 0) {
window.location.href = "/";
return;
}

var ecosystem = resp.rows[0];
document.title = ecosystem.name + " | WAXBadges Achievements Explorer"
$("meta[property='og:title']").attr("content", ecosystem.name + " | WAXBadges Achievements Explorer");
$("meta[property='og:description']").attr("content", ecosystem.description);
$("meta[name='twitter:card'][content='summary']").text(ecosystem.description);
$("#ecosystem_name").text(ecosystem.name);
$("#ecosystem_website").append("<a href='" + ecosystem.website + "' target='_new'>" + ecosystem.website + "</a>");
$("#ecosystem_description").text(ecosystem.description);

for (var i=0; i < ecosystem.categories.length; i++) {
let category = ecosystem.categories[i];
console.log(category);

let $cat_template = $(".category_template").clone().appendTo("#category_list");
$cat_template.attr("id", "cat_" + i);
$cat_template.find(".cat_name").text(category.name);
$cat_template.show();

for (var j=0; j < category.achievements.length; j++) {
let achievement = category.achievements[j];
console.log(achievement);
let $ach_template = $(".achievement_template").first().clone();
$ach_template.insertBefore($cat_template.find('.ach_list .clearfix'));
$ach_template = $ach_template.attr("id", "cat_" + i + "_ach_" + j);
$ach_template.find(".ach_name").text(achievement.name);
$ach_template.find(".ach_asset").attr("src", "//" + ecosystem.assetbaseurl + "/" + achievement.assetname);

if (achievement.maxquantity != "0") {
$ach_template.find(".ach_quantity").text("max: " + achievement.maxquantity);
} else {
$ach_template.find(".ach_quantity").text("unlimited");
}

$ach_template.find(".ach_description").text(achievement.description);
$ach_template.show();
}
}

$("#ecosystem_container").show();
}



$(document).ready(function() {

signatureProvider = new JsSignatureProvider([PRIVATE_KEY]);
api = new Api({ rpc, signatureProvider });

$(".account_name").text(ACCOUNT_NAME);

pageoverlay = new PageOverlay();

let pathParts = window.location.pathname.split('/', 3);
let page = pathParts[1];
var param;
if (page != "") {
param = parseInt(pathParts[2]);
}
if (page == 'ecosys') {
renderEcosys(param);
} else {
renderIndex();
}

});



@@ -0,0 +1,87 @@
let $ = require("jquery");


class PageOverlay {
constructor() {
const style = `
<style>
.page_overlay {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0, 0.75);
text-align: center;
z-index: 20;
}
.page_overlay_popup {
display: none;
opacity: 0.0;
margin: 0 auto;
max-width: 650px;
text-align: center;
border-radius: 3em;
border: 5px solid #6cc7cc;
background-color: #eee;
padding: 0.5em;
padding-bottom: 1.5em;
z-index: 30;
}
</style>
`;
const content = `
<div class="page_overlay" id="page_overlay">
<div class="page_overlay_popup" id="page_overlay_popup">
<div id="page_overlay_popup_content"></div>
<!--div class="float_right"><div id="page_overlay_popup_cancel_button" class="stylized_button stylized_button_tiny">cancel</div></div-->
<br/>
<div class="clear-both"></div>
</div>
</div>
`;
document.head.insertAdjacentHTML('beforeend', style);
document.body.insertAdjacentHTML('beforeend', content);
}

initPageOverlay(content_selector) {
// Transfer the content to a new hidden div
var $holder = $("<div/>").hide().appendTo("body");
$(content_selector).appendTo($holder);

// Make sure the content will be visible, even though it'll still be hidden in its parent div.
$(content_selector).show();
}


showPageOverlay(content_selector) {
// Transfer the content to the popup overlay div
$(content_selector).appendTo($("#page_overlay_popup_content"));
$("#page_overlay").show();

var top_position = (window.innerHeight/2) - $("#page_overlay_popup").height();
if (top_position < 20) { top_position = 20; }
$("#page_overlay_popup").css({
"position": "relative",
"display": "block",
"top": top_position,
});

window.scrollTo(0, 0);
$("#page_overlay_popup").animate({opacity:1.0}, 500);
}


hidePageOverlay() {
// Transfer the content back into a holder div
this.initPageOverlay($("#page_overlay_popup_content").children());

$("#page_overlay").hide();
$("#page_overlay_popup").css({opacity:0.0});
}

}


module.exports = PageOverlay

0 comments on commit 46cb81d

Please sign in to comment.
You can’t perform that action at this time.