new site
81
website/404/index.html
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-P53NSV9J65');
|
||||||
|
</script>
|
||||||
|
<title>Grinminer.net</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="title" property="og:title" content="grinminer.net">
|
||||||
|
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||||
|
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||||
|
<meta name="theme-color" content="#fef102">
|
||||||
|
<!-- CSS Main -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body width="device-width">
|
||||||
|
<!-- Load an icon library to show a hamburger menu (bars) on small screens -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
|
||||||
|
<!--Navigation links-->
|
||||||
|
<div class="topnav" id="myTopnav">
|
||||||
|
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||||
|
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||||
|
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||||
|
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||||
|
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||||
|
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||||
|
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||||
|
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||||
|
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||||
|
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||||
|
|
||||||
|
<!--Banner-->
|
||||||
|
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||||
|
|
||||||
|
<!--Subtitle-->
|
||||||
|
<div class="content">
|
||||||
|
<div class="subtitle">
|
||||||
|
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||||
|
</div>
|
||||||
|
<div class="corporate">
|
||||||
|
<p>Host of Grin's permanent public testnet mining node allowing devs to have 24/7 block production, aiding development of the protocol.</p>
|
||||||
|
</div>
|
||||||
|
<p>VPS service with no KYC, customer logs, contracts, or corporate ties.</p>
|
||||||
|
<div id="corporate">
|
||||||
|
<span class="corporate"><p>Grinminer.net is not controlled by any company or foundation.</p></span>
|
||||||
|
</div>
|
||||||
|
<h1 class="fourohfour">404 NOT FOUND</h1>
|
||||||
|
<img src="../images/grinminerbanner.png" alt="grinminer ad" class="ad">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<footer width="device-width">
|
||||||
|
<div class="footer">
|
||||||
|
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||||
|
<p>mikkdfjjawqzw4bis5pwq
|
||||||
|
<br>
|
||||||
|
wsbul3ndubhnbwtlumaeo
|
||||||
|
<br>
|
||||||
|
wlcigxgwk7n4yd.onion</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
88
website/api/index.html
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-P53NSV9J65');
|
||||||
|
</script>
|
||||||
|
<title>Grinminer.net</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="title" property="og:title" content="grinminer.net">
|
||||||
|
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||||
|
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||||
|
<meta name="theme-color" content="#fef102">
|
||||||
|
<!-- CSS Main -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body width="device-width">
|
||||||
|
<!--Navigation links-->
|
||||||
|
<div class="topnav" id="myTopnav">
|
||||||
|
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||||
|
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||||
|
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||||
|
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||||
|
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||||
|
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||||
|
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||||
|
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||||
|
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||||
|
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||||
|
|
||||||
|
|
||||||
|
<!--Banner-->
|
||||||
|
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||||
|
<!--Subtitle-->
|
||||||
|
<div class="content">
|
||||||
|
<div class="subtitle">
|
||||||
|
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||||
|
</div>
|
||||||
|
<h1>Grinminer public APIs</h1>
|
||||||
|
<p>no API secret required</p>
|
||||||
|
<h2>Mainnet</h2>
|
||||||
|
<h3>http://grinminer.net:3413</h3>
|
||||||
|
<h2>Testnet</h2>
|
||||||
|
<h3>http://grinminer.net:13413</h3>
|
||||||
|
<a href="https://github.com/mimblewimble/grin/blob/master/doc/api/node_api_v1.md">Grin node api v1 documentation</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://docs.grin.mw/grin-rfcs/text/0007-node-api-v2/">Grin node api v2 documentation</a>
|
||||||
|
<script>
|
||||||
|
function myFunction() {
|
||||||
|
var x = document.getElementById("myTopnav");
|
||||||
|
if (x.className === "topnav") {
|
||||||
|
x.className += " responsive"; // Add the "responsive" class
|
||||||
|
} else {
|
||||||
|
x.className = "topnav"; // Remove the "responsive" class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<footer width="device-width">
|
||||||
|
<div class="footer">
|
||||||
|
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||||
|
<p>mikkdfjjawqzw4bis5pwq
|
||||||
|
<br>
|
||||||
|
wsbul3ndubhnbwtlumaeo
|
||||||
|
<br>
|
||||||
|
wlcigxgwk7n4yd.onion</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
127
website/application/index.html
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-P53NSV9J65');
|
||||||
|
</script>
|
||||||
|
<title>Grinminer.net</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="title" property="og:title" content="grinminer.net">
|
||||||
|
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||||
|
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||||
|
<meta name="theme-color" content="#fef102">
|
||||||
|
<!-- CSS Main -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body width="device-width">
|
||||||
|
<!--Navigation links-->
|
||||||
|
<<div class="topnav" id="myTopnav">
|
||||||
|
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||||
|
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||||
|
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||||
|
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||||
|
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||||
|
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||||
|
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||||
|
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||||
|
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||||
|
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||||
|
|
||||||
|
|
||||||
|
<!--Banner-->
|
||||||
|
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||||
|
<!--Subtitle-->
|
||||||
|
<div class="content">
|
||||||
|
<div class="subtitle">
|
||||||
|
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||||
|
</div>
|
||||||
|
<!--Title-->
|
||||||
|
<form action="https://formsubmit.co/fc6589379f42ab354825f1184623a4eb" method="POST" style="border:1px solid #ccc">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Sign Up</h1>
|
||||||
|
<p>Please fill in this form to create an account.</p>
|
||||||
|
<p>Fees are nominal, and meant to discourage resource waste. Must be paid in Grin.</p>
|
||||||
|
<p>All nodes are LXC containers running the latest Debian release.</p>
|
||||||
|
<br>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Are you looking for a Grin node or node+stratum?</legend>
|
||||||
|
<label><input id="node" type="radio" name="node" value="node" checked>Node only</label>
|
||||||
|
<label><input id="node+stratum" type="radio" name="node" value="stratum">Node+Stratum</label>
|
||||||
|
</fieldset>
|
||||||
|
<br>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Do you want an archival or pruned node?</legend>
|
||||||
|
<input id="pruned" type="radio" name="type" value="pruned" checked> <label for="pruned">Pruned (free)</label>
|
||||||
|
<input id="full" type="radio" name="type" value="archival"> <label for="archival">Archival (flat fee)</label>
|
||||||
|
</fieldset>
|
||||||
|
<br>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Do you require node setup or support/backups?</legend>
|
||||||
|
<input id="no" type="radio" name="support" value="no" checked> <label for="no">None (free)</label>
|
||||||
|
<input id="setup" type="radio" name="support" value="setup"> <label for="setup">Setup only (flat fee)</label>
|
||||||
|
<input id="setup+support" type="radio" name="support" value="ongoing"> <label for="ongoing"> Ongoing support/backups (monthly fee)</label>
|
||||||
|
</fieldset>
|
||||||
|
<br>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Do you agree to only use your VPS for Grin software?</legend>
|
||||||
|
<input id="no-agreement" type="radio" name="agreement" value="no" checked> <label for="no">No (comment why)</label>
|
||||||
|
<input id="agreement" type="radio" name="agreement" value="yes"> <label for="yes">Yes</label>
|
||||||
|
</fieldset>
|
||||||
|
<br>
|
||||||
|
<input type="text" name="username" placeholder="username" required>
|
||||||
|
<br>
|
||||||
|
<input type="text" name="email" placeholder="email address" required>
|
||||||
|
<br>
|
||||||
|
<input type="text" name="comments" placeholder="comments">
|
||||||
|
<input type="hidden" name="_next" value="https://grinminer.net/thanks.html">
|
||||||
|
<input type="hidden" name="_subject" value="Grinminer application">
|
||||||
|
<p>Grinminer.net is very young and experimental, use at your own risk.</p>
|
||||||
|
<p>Once applied you will receive an email response within 48 hours to confirm.</p>
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<button type="submit" class="signupbtn">Sign Up</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
function myFunction() {
|
||||||
|
var x = document.getElementById("myTopnav");
|
||||||
|
if (x.className === "topnav") {
|
||||||
|
x.className += " responsive"; // Add the "responsive" class
|
||||||
|
} else {
|
||||||
|
x.className = "topnav"; // Remove the "responsive" class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<footer width="device-width">
|
||||||
|
<div class="footer">
|
||||||
|
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||||
|
<p>mikkdfjjawqzw4bis5pwq
|
||||||
|
<br>
|
||||||
|
wsbul3ndubhnbwtlumaeo
|
||||||
|
<br>
|
||||||
|
wlcigxgwk7n4yd.onion</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
BIN
website/firmware/SDCARD-IPollo-G1-2.5.4-firmware.img
Normal file
BIN
website/firmware/SDCARD-Ipollo-G1-2.5.2-firmware.bin
Normal file
2479
website/firmware/WEBFLASH-Ipollo-G1-2.4.0-firmware.bin
Normal file
2479
website/firmware/WEBFLASH-Ipollo-G1-2.4.4-firmware.bin
Normal file
1861
website/firmware/WEBFLASH-Ipollo-G1-2.4.9-firmware.bin
Normal file
BIN
website/firmware/WEBFLASH-Ipollo-G1-2.5.2-firmware.img
Normal file
BIN
website/firmware/WEBFLASH-Ipollo-G1-2.5.4-firmware.bin
Normal file
11
website/grinminer-form/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "grinminer-form"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = { git = "https://github.com/rwf2/Rocket" }
|
||||||
|
|
||||||
|
[dependencies.rocket_dyn_templates]
|
||||||
|
version = "0.1.0"
|
||||||
|
features = ["handlebars", "tera", "minijinja"]
|
151
website/grinminer-form/index.html
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
** start of undefined **
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="styles.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header class="header">
|
||||||
|
<h1 id="title" class="text-center">Grinminer.net application</h1>
|
||||||
|
<p id="description" class="description text-center">
|
||||||
|
Apply for a free or paid node/stratum depending on support level
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<form id="survey-form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label id="name-label" for="name">Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Enter your name"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label id="email-label" for="email">Email</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Enter your Email"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label id="number-label" for="number">Number of nodes<span class="clue">(max 4)</span></label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="nodes"
|
||||||
|
id="number"
|
||||||
|
min="1"
|
||||||
|
max="4"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="node"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<p>Select an option</p>
|
||||||
|
<select id="dropdown" name="stratum" class="form-control" required>
|
||||||
|
<option disabled selected value>Select features</option>
|
||||||
|
<option value="testnet">Testnet node</option>
|
||||||
|
<option value="testnet">Testnet node+mwixnet</option>
|
||||||
|
<option value="pruned">Pruned node</option>
|
||||||
|
<option value="node+stratum">Pruned node+stratum</option>
|
||||||
|
<option value="fullnode">Full node (10ツ)</option>
|
||||||
|
<option value="fullnode+stratum">Full node+stratum(10ツ)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<p>Do you need setup help and ongoing support your node(s)?</p>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
name="setup"
|
||||||
|
value="no"
|
||||||
|
type="radio"
|
||||||
|
class="input-radio"
|
||||||
|
checked
|
||||||
|
/>No</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
name="setup"
|
||||||
|
value="yes"
|
||||||
|
type="radio"
|
||||||
|
class="input-radio"
|
||||||
|
checked
|
||||||
|
/>Yes (25ツ)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<p>Do you agree to only use this VPS for Grin?</p>
|
||||||
|
<select id="agreement" name="agreement" class="form-control" required>
|
||||||
|
<option disabled selected value>Select an option</option>
|
||||||
|
<option value="challenges">Yes</option>
|
||||||
|
<option value="projects">No</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<p>What future features are you interested in?<span class="clue">(Check all that apply)</span></p>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
name="prefer"
|
||||||
|
value="firmware-update"
|
||||||
|
type="checkbox"
|
||||||
|
class="input-checkbox"
|
||||||
|
/>Updated firmware</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
name="prefer"
|
||||||
|
value="firmware-overclock"
|
||||||
|
type="checkbox"
|
||||||
|
class="input-checkbox"
|
||||||
|
/>Overclocked firmware</label
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
><input
|
||||||
|
name="prefer"
|
||||||
|
value="stratumv2"
|
||||||
|
type="checkbox"
|
||||||
|
class="input-checkbox"
|
||||||
|
/>Stratum V2</label
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
><input
|
||||||
|
name="prefer"
|
||||||
|
value="controlpanel"
|
||||||
|
type="checkbox"
|
||||||
|
class="input-checkbox"
|
||||||
|
/>Mining control panel</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<p>Comments or suggestions?</p>
|
||||||
|
<textarea
|
||||||
|
id="comments"
|
||||||
|
class="input-textarea"
|
||||||
|
name="comment"
|
||||||
|
placeholder="Enter your comments here..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" id="submit" class="submit-button">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
** end of undefined **
|
||||||
|
|
||||||
|
** start of undefined **
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
** end of undefined **
|
||||||
|
|
97
website/grinminer-form/src/main.rs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#[macro_use] extern crate rocket;
|
||||||
|
|
||||||
|
use rocket::time::Date;
|
||||||
|
use rocket::http::{Status, ContentType};
|
||||||
|
use rocket::form::{Form, Contextual, FromForm, FromFormField, Context};
|
||||||
|
use rocket::fs::{FileServer, TempFile, relative};
|
||||||
|
|
||||||
|
use rocket_dyn_templates::Template;
|
||||||
|
|
||||||
|
#[derive(Debug, FromForm)]
|
||||||
|
struct Password<'v> {
|
||||||
|
#[field(validate = len(6..))]
|
||||||
|
#[field(validate = eq(self.second))]
|
||||||
|
#[allow(unused)]
|
||||||
|
first: &'v str,
|
||||||
|
#[allow(unused)]
|
||||||
|
#[field(validate = eq(self.first))]
|
||||||
|
second: &'v str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromFormField)]
|
||||||
|
enum Rights {
|
||||||
|
Public,
|
||||||
|
Reserved,
|
||||||
|
Exclusive,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromFormField)]
|
||||||
|
enum Category {
|
||||||
|
Biology,
|
||||||
|
Chemistry,
|
||||||
|
Physics,
|
||||||
|
#[field(value = "CS")]
|
||||||
|
ComputerScience,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromForm)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Submission<'v> {
|
||||||
|
#[field(validate = len(1..))]
|
||||||
|
title: &'v str,
|
||||||
|
date: Date,
|
||||||
|
#[field(validate = len(1..=250))]
|
||||||
|
r#abstract: &'v str,
|
||||||
|
#[field(validate = ext(ContentType::PDF))]
|
||||||
|
file: TempFile<'v>,
|
||||||
|
#[field(validate = len(1..))]
|
||||||
|
category: Vec<Category>,
|
||||||
|
rights: Rights,
|
||||||
|
ready: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromForm)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Account<'v> {
|
||||||
|
#[field(validate = len(1..))]
|
||||||
|
name: &'v str,
|
||||||
|
password: Password<'v>,
|
||||||
|
#[field(validate = contains('@').or_else(msg!("invalid email address")))]
|
||||||
|
email: &'v str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromForm)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Submit<'v> {
|
||||||
|
account: Account<'v>,
|
||||||
|
submission: Submission<'v>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
fn index() -> Template {
|
||||||
|
Template::render("index", &Context::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: We use `Contextual` here because we want to collect all submitted form
|
||||||
|
// fields to re-render forms with submitted values on error. If you have no such
|
||||||
|
// need, do not use `Contextual`. Use the equivalent of `Form<Submit<'_>>`.
|
||||||
|
#[post("/", data = "<form>")]
|
||||||
|
fn submit<'r>(form: Form<Contextual<'r, Submit<'r>>>) -> (Status, Template) {
|
||||||
|
let template = match form.value {
|
||||||
|
Some(ref submission) => {
|
||||||
|
println!("submission: {:#?}", submission);
|
||||||
|
Template::render("success", &form.context)
|
||||||
|
}
|
||||||
|
None => Template::render("index", &form.context),
|
||||||
|
};
|
||||||
|
|
||||||
|
(form.context.status(), template)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[launch]
|
||||||
|
fn rocket() -> _ {
|
||||||
|
rocket::build()
|
||||||
|
.mount("/", routes![index, submit])
|
||||||
|
.attach(Template::fairing())
|
||||||
|
.mount("/", FileServer::from(relative!("/static")))
|
||||||
|
}
|
193
website/grinminer-form/src/tests.rs
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use super::{rocket, FormInput, FormOption};
|
||||||
|
|
||||||
|
use rocket::local::blocking::Client;
|
||||||
|
use rocket::http::ContentType;
|
||||||
|
|
||||||
|
impl fmt::Display for FormOption {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
FormOption::A => write!(f, "a"),
|
||||||
|
FormOption::B => write!(f, "b"),
|
||||||
|
FormOption::C => write!(f, "c"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_form_eq {
|
||||||
|
($client:expr, $form_str:expr, $expected:expr) => {{
|
||||||
|
let res = $client.post("/")
|
||||||
|
.header(ContentType::Form)
|
||||||
|
.body($form_str)
|
||||||
|
.dispatch();
|
||||||
|
|
||||||
|
assert_eq!(res.into_string(), Some($expected));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_valid_form {
|
||||||
|
($client:expr, $input:expr) => {{
|
||||||
|
let f = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
|
||||||
|
$input.checkbox, $input.number, $input.radio, $input.password,
|
||||||
|
$input.text_area, $input.select);
|
||||||
|
assert_form_eq!($client, &f, format!("{:?}", $input));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_valid_raw_form {
|
||||||
|
($client:expr, $form_str:expr, $input:expr) => {{
|
||||||
|
assert_form_eq!($client, $form_str, format!("{:?}", $input));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_good_forms() {
|
||||||
|
let client = Client::tracked(rocket()).unwrap();
|
||||||
|
let mut input = FormInput {
|
||||||
|
checkbox: true,
|
||||||
|
number: 310,
|
||||||
|
radio: FormOption::A,
|
||||||
|
password: "beep".into(),
|
||||||
|
text_area: "bop".to_string(),
|
||||||
|
select: FormOption::B
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
input.checkbox = false;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
input.number = 0;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.number = 120;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.number = 133;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
input.radio = FormOption::B;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.radio = FormOption::C;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
input.password = "".into();
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.password = "----90138490285u2o3hndslkv".into();
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.password = "hi".into();
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
input.text_area = "".to_string();
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.text_area = "----90138490285u2o3hndslkv".to_string();
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.text_area = "hey".to_string();
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
input.select = FormOption::A;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
input.select = FormOption::C;
|
||||||
|
assert_valid_form!(&client, &input);
|
||||||
|
|
||||||
|
// checkbox need not be present; defaults to false; accepts 'on' and 'off'
|
||||||
|
assert_valid_raw_form!(&client,
|
||||||
|
"number=133&type=c&password=hi&textarea=hey&select=c",
|
||||||
|
&input);
|
||||||
|
|
||||||
|
assert_valid_raw_form!(&client,
|
||||||
|
"checkbox=off&number=133&type=c&password=hi&textarea=hey&select=c",
|
||||||
|
&input);
|
||||||
|
|
||||||
|
input.checkbox = true;
|
||||||
|
assert_valid_raw_form!(&client,
|
||||||
|
"checkbox=on&number=133&type=c&password=hi&textarea=hey&select=c",
|
||||||
|
&input);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_invalid_form {
|
||||||
|
($client:expr, $vals:expr) => {{
|
||||||
|
let vals = $vals;
|
||||||
|
let s = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
|
||||||
|
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
|
||||||
|
assert_form_eq!($client, &s, format!("Invalid form input: {}", s));
|
||||||
|
*vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_invalid_raw_form {
|
||||||
|
($client:expr, $form_str:expr) => {{
|
||||||
|
assert_form_eq!($client, $form_str, format!("Invalid form input: {}", $form_str));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_semantically_invalid_forms() {
|
||||||
|
let client = Client::tracked(rocket()).unwrap();
|
||||||
|
let mut form_vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||||
|
|
||||||
|
form_vals[0] = "not true";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[0] = "bing";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[0] = "true0";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[0] = " false";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
|
||||||
|
form_vals[1] = "-1";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[1] = "1e10";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[1] = "-1-1";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[1] = "NaN";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
|
||||||
|
form_vals[2] = "A?";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[2] = " B";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[2] = "d";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[2] = "100";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[2] = "";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
|
||||||
|
// password and textarea are always valid, so we skip them
|
||||||
|
form_vals[5] = "A.";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[5] = "b ";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[5] = "d";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[5] = "-a";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
form_vals[5] = "";
|
||||||
|
assert_invalid_form!(&client, &mut form_vals);
|
||||||
|
|
||||||
|
// now forms with missing fields
|
||||||
|
assert_invalid_raw_form!(&client, "number=10&type=a&password=hi&textarea=hey");
|
||||||
|
assert_invalid_raw_form!(&client, "number=10&radio=a&password=hi&textarea=hey&select=b");
|
||||||
|
assert_invalid_raw_form!(&client, "number=10&password=hi&select=b");
|
||||||
|
assert_invalid_raw_form!(&client, "number=10&select=b");
|
||||||
|
assert_invalid_raw_form!(&client, "password=hi&select=b");
|
||||||
|
assert_invalid_raw_form!(&client, "password=hi");
|
||||||
|
assert_invalid_raw_form!(&client, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_structurally_invalid_forms() {
|
||||||
|
let client = Client::tracked(rocket()).unwrap();
|
||||||
|
assert_invalid_raw_form!(&client, "==&&&&&&==");
|
||||||
|
assert_invalid_raw_form!(&client, "a&=b");
|
||||||
|
assert_invalid_raw_form!(&client, "=");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_bad_utf8() {
|
||||||
|
let client = Client::tracked(rocket()).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let bad_str = std::str::from_utf8_unchecked(b"a=\xff");
|
||||||
|
assert_form_eq!(&client, bad_str, "Form input was invalid UTF-8.".into());
|
||||||
|
}
|
||||||
|
}
|
1
website/grinminer-form/static/chota.min.css
vendored
Normal file
148
website/grinminer-form/templates/index.html.tera
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
{% import "macros" as m %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<title>Rocket Form Example</title>
|
||||||
|
<link rel="stylesheet" href="/chota.min.css">
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Form Example</h1>
|
||||||
|
|
||||||
|
{% if errors | length > 0 %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<small class="text-error">
|
||||||
|
error: {{ errors | length }} field{{ errors | length | pluralize }}
|
||||||
|
failed to validate
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="/" method="post" enctype="multipart/form-data">
|
||||||
|
<fieldset>
|
||||||
|
<legend>About You</legend>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ m::input(label="Name", type="text", name="account.name") }}
|
||||||
|
<!-- required -->
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ m::input(label="Email Address", type="text", name="account.email") }}
|
||||||
|
<!-- required pattern=".*@.*"/> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ m::input(label="Password", type="password", name="account.password.first") }}
|
||||||
|
<!-- required minlength="6" value="" /> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
{{
|
||||||
|
m::input(label="Confirm Password",
|
||||||
|
type="password",
|
||||||
|
name="account.password.second")
|
||||||
|
}}
|
||||||
|
|
||||||
|
<!-- required minlength="6" value="" /> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Metadata</legend>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ m::input(label="Title", type="text", name="submission.title") }}
|
||||||
|
<!-- required -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ m::input(label="Publish Date", type="date", name="submission.date") }}
|
||||||
|
<!-- <input type="date" name="submission.date" id="date" value="2020-12-26"> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
{{
|
||||||
|
m::select(
|
||||||
|
label="Rights Assignment",
|
||||||
|
name="submission.rights",
|
||||||
|
options=["Public", "Reserved", "Exclusive"]
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<label>Applicable Categories</label>
|
||||||
|
<br />
|
||||||
|
{{ m::checkbox(name="submission.category", label="Biology", value="Biology") }}
|
||||||
|
<br />
|
||||||
|
{{ m::checkbox(name="submission.category", label="Chemistry", value="Chemistry") }}
|
||||||
|
<br />
|
||||||
|
{{ m::checkbox(name="submission.category", label="Physics", value="Physics") }}
|
||||||
|
<br />
|
||||||
|
{{ m::checkbox(name="submission.category", label="CS", value="CS") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Contents</legend>
|
||||||
|
|
||||||
|
{{
|
||||||
|
m::textarea(
|
||||||
|
label="Abstract",
|
||||||
|
name="submission.abstract",
|
||||||
|
placeholder="Your abstract, max 250 characters...",
|
||||||
|
max=250
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{
|
||||||
|
m::input(
|
||||||
|
label="File to Upload (PDF, max 1MiB)",
|
||||||
|
type="file",
|
||||||
|
name="submission.file"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
|
||||||
|
<!-- <input type="file" name="submission.file" id="file" required accept=".pdf"> -->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ m::checkbox(name="submission.ready", label="Submission is ready for review.") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Submit" class="is-full-width" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
63
website/grinminer-form/templates/macros.html.tera
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{% macro value_for(name) %}
|
||||||
|
{%- if name in values -%}
|
||||||
|
{{- values | get(key=name) | first -}}
|
||||||
|
{%- endif -%}
|
||||||
|
{% endmacro value_for %}
|
||||||
|
|
||||||
|
{% macro errors_for(name) %}
|
||||||
|
{%- if name in errors -%}
|
||||||
|
{% set field_errors = errors | get(key=name) %}
|
||||||
|
{% for error in field_errors %}
|
||||||
|
<p class="text-error is-marginless">{{ error.msg }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{%- endif -%}
|
||||||
|
{% endmacro errors_for %}
|
||||||
|
|
||||||
|
{% macro input(type, label, name, value="") %}
|
||||||
|
<label for="{{ name }}">{{ label }}</label>
|
||||||
|
<input type="{{ type }}"
|
||||||
|
name="{{ name }}"
|
||||||
|
id="{{ name }}"
|
||||||
|
value='{{ self::value_for(name=name) }}'
|
||||||
|
{% if name in errors %} class="error" {% endif %}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{ self::errors_for(name=name) }}
|
||||||
|
{% endmacro input %}
|
||||||
|
|
||||||
|
{% macro checkbox(name, label, value="yes") %}
|
||||||
|
<label {% if name in errors %} class="bd-error" {% endif %}>
|
||||||
|
<input type="checkbox" name="{{ name }}" value={{ value }}
|
||||||
|
{% if name in values %}
|
||||||
|
{% set field_values = values | get(key=name) %}
|
||||||
|
{% if field_values is containing(value) %}
|
||||||
|
checked
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</label>
|
||||||
|
{% endmacro checkbox %}
|
||||||
|
|
||||||
|
{% macro textarea(label, name, placeholder="", max=250) %}
|
||||||
|
<label for="{{ name }}">{{ label }}</label>
|
||||||
|
<textarea placeholder="{{ placeholder }}"
|
||||||
|
name="{{ name }}" id="{{ name }}" rows="8" cols="40"
|
||||||
|
{% if name in errors %} class="error" {% endif %}
|
||||||
|
>
|
||||||
|
{{- self::value_for(name=name) -}}
|
||||||
|
</textarea>
|
||||||
|
|
||||||
|
{{ self::errors_for(name=name) }}
|
||||||
|
{% endmacro textarea %}
|
||||||
|
|
||||||
|
{% macro select(label, name, options) %}
|
||||||
|
<label for="{{ name }}">{{ label }}</label>
|
||||||
|
<select name="{{ name }}" id="{{ name }}">
|
||||||
|
{% for value in options %}
|
||||||
|
<option value="{{ value }}"
|
||||||
|
{% if self::value_for(name=name) == value %} selected {% endif %}
|
||||||
|
>{{ value }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
{% endmacro select %}
|
30
website/grinminer-form/templates/success.html.tera
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<title>Rocket Form Example</title>
|
||||||
|
<link rel="stylesheet" href="/chota.min.css">
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Success!</h1>
|
||||||
|
|
||||||
|
<h3>Submission Data</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for key, value in values %}
|
||||||
|
<li><strong>{{ key }}</strong> - {{ value }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a href="/">< Submit Another</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
website/images/gpp.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
website/images/grim.png
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
website/images/grin-logo-cat-cropped-black.png
Normal file
After Width: | Height: | Size: 84 KiB |
1605
website/images/grin-logo-cat.svg
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
website/images/grinminerbanner.png
Normal file
After Width: | Height: | Size: 622 KiB |
BIN
website/images/ipollo.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
website/images/network.png
Normal file
After Width: | Height: | Size: 252 KiB |
4
website/images/network.svg
Normal file
After Width: | Height: | Size: 4.3 MiB |
BIN
website/images/web-banner.png
Executable file
After Width: | Height: | Size: 128 KiB |
224
website/main.css
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Lato", sans-serif;
|
||||||
|
background-color: black;
|
||||||
|
color: #fef102;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: whitesmoke;
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
width: 430px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a black background color to the top navigation */
|
||||||
|
.topnav {
|
||||||
|
background-color: #333;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the links inside the navigation bar */
|
||||||
|
.topnav a {
|
||||||
|
float: left;
|
||||||
|
display: block;
|
||||||
|
color: whitesmoke;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the color of links on hover */
|
||||||
|
.topnav a:hover {
|
||||||
|
background-color: #fef102;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an active class to highlight the current page */
|
||||||
|
.topnav a.active {
|
||||||
|
background-color: #fef102;
|
||||||
|
color: black;
|
||||||
|
border-right: black 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an active class to highlight the current page */
|
||||||
|
.topnav a.grey {
|
||||||
|
border-right: black 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive {
|
||||||
|
max-width: 90%;
|
||||||
|
height: auto;
|
||||||
|
margin: 0 auto;
|
||||||
|
border: #fef102 solid 4px;
|
||||||
|
border-radius: 30px;
|
||||||
|
box-shadow:0 0 10px #fef102;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagram {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fourohfour {
|
||||||
|
font-size: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ad {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 16px
|
||||||
|
font-weight: 800;
|
||||||
|
border: #fef102 solid 4px;
|
||||||
|
border-radius: 0 0 15px 15px;
|
||||||
|
box-shadow: 0 0 10px #fef102;
|
||||||
|
width: 70%;
|
||||||
|
height: auto;
|
||||||
|
margin: -5px auto 30px auto;
|
||||||
|
display: block;
|
||||||
|
text-align:center;
|
||||||
|
padding: 0 40px 0 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1px 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cloud {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
color: black;
|
||||||
|
display: block;
|
||||||
|
background-color: #fef102;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodes {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site.pad.community-pad{
|
||||||
|
padding-top:40px;
|
||||||
|
padding-bottom:40px;
|
||||||
|
border-top:1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community {
|
||||||
|
background-color:black;
|
||||||
|
padding:-10px 16px 64px 16px;
|
||||||
|
max-width:700px;
|
||||||
|
margin:0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community a {
|
||||||
|
border-bottom:1px solid black
|
||||||
|
}
|
||||||
|
|
||||||
|
.community h2 {
|
||||||
|
text-align:center
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-subheading {
|
||||||
|
line-height:1.4em;
|
||||||
|
text-align:center
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-content {
|
||||||
|
margin-top:40px;
|
||||||
|
background-color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-row {
|
||||||
|
padding:20px;
|
||||||
|
margin: 5px 0 5px 0;
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border: solid 1px silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-row-img {
|
||||||
|
height:80px;
|
||||||
|
width:80px;
|
||||||
|
margin-right:16px;
|
||||||
|
border-radius:15px
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-row-content {
|
||||||
|
margin-top:4px
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-row-heading {
|
||||||
|
font-size:18px;
|
||||||
|
font-weight:bold;
|
||||||
|
margin-bottom:4px
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-row-desc {
|
||||||
|
line-height:1.4em;
|
||||||
|
margin-bottom:8px
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-row-category {
|
||||||
|
color:#6F6F6F;
|
||||||
|
font-size:12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav {
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav a {
|
||||||
|
float: left;
|
||||||
|
display: block;
|
||||||
|
color: whitesmoke;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav a:hover {
|
||||||
|
background-color: #fef102;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topnav .icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive styles */
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.topnav a {
|
||||||
|
display: none; /* Hide all links by default */
|
||||||
|
}
|
||||||
|
.topnav a.icon {
|
||||||
|
float: right;
|
||||||
|
display: block; /* Show the hamburger icon */
|
||||||
|
color: #fef102;
|
||||||
|
}
|
||||||
|
.topnav.responsive {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.topnav.responsive a {
|
||||||
|
display: block; /* Show links when the menu is responsive */
|
||||||
|
float: none; /* Remove float */
|
||||||
|
}
|
||||||
|
}
|
87
website/thanks.html
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-P53NSV9J65');
|
||||||
|
</script>
|
||||||
|
<title>Grinminer.net</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="title" property="og:title" content="grinminer.net">
|
||||||
|
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||||
|
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||||
|
<meta name="theme-color" content="#fef102">
|
||||||
|
<!-- CSS Main -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body width="device-width">
|
||||||
|
<body width="device-width">
|
||||||
|
<!-- Load an icon library to show a hamburger menu (bars) on small screens -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
|
||||||
|
<!--Navigation links-->
|
||||||
|
<div class="topnav" id="myTopnav">
|
||||||
|
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||||
|
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||||
|
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||||
|
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||||
|
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||||
|
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||||
|
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||||
|
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||||
|
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||||
|
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||||
|
|
||||||
|
<!--Banner-->
|
||||||
|
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||||
|
|
||||||
|
<!--Subtitle-->
|
||||||
|
<div class="content">
|
||||||
|
<div class="subtitle">
|
||||||
|
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||||
|
</div>
|
||||||
|
<!--Title-->
|
||||||
|
<div class="nodes">
|
||||||
|
<h1>Thank you! Expect a response within 48hr.</h1>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function myFunction() {
|
||||||
|
var x = document.getElementById("myTopnav");
|
||||||
|
if (x.className === "topnav") {
|
||||||
|
x.className += " responsive"; // Add the "responsive" class
|
||||||
|
} else {
|
||||||
|
x.className = "topnav"; // Remove the "responsive" class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<footer width="device-width">
|
||||||
|
<div class="footer">
|
||||||
|
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||||
|
<p>mikkdfjjawqzw4bis5pwq
|
||||||
|
<br>
|
||||||
|
wsbul3ndubhnbwtlumaeo
|
||||||
|
<br>
|
||||||
|
wlcigxgwk7n4yd.onion</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|