Implement donation redirection to backend
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 22 May 2018 14:32:04 +0000 (16:32 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 22 May 2018 14:32:56 +0000 (16:32 +0200)
This will enhance the donation form to form a request
which is being sent to Zeiterfassung which handles
the rest of the payment process.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
templates/donate.html
webapp/backend/base.py
webapp/backend/zeiterfassung.py [new file with mode: 0644]
webapp/handlers.py

index d4afd9c..0e680a5 100644 (file)
                        <div class="row">
                                <section class="features-content col-12 text-center">
                                        <h2 class="display-2">{{ _("Donate") }}</h2>
-                                       
-                                       <div class="row justify-content-center mb-6">
-                                               <div class="col-12 col-sm-11 col-xl-12">
-                                                       <div class="row">
-                                                               <div class="donation-card d-flex flex-column flex-md-row-reverse text-left col p-0">
-                                                                       <div class="card p-4 p-sm-6 p-md-4 pt-6">
-                                                                               <div class="row py-md-3 px-md-6">
-                                                                                       <div class="col-12 col-lg-6 d-flex flex-column mb-6 mb-lg-0">
-                                                                                               <h4 class="mb-5">Choose a currency</h4>
-                                                                                               <div class="row pt-4">
-                                                                                                       <div class="col col-sm-4 col-md-5">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="currency" id="euro" value="euro" checked>
-                                                                                                               <label for="euro" class="form-check-label radiobtn">€uro</label>
-                                                                                                       </div>
-                                                                                                       <div class="col col-sm-4 col-md-5">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="currency" id="usd" value="usd">
-                                                                                                               <label for="usd" class="form-check-label radiobtn">USD $</label>
+
+                                       <form action="" method="POST">
+                                               {% raw xsrf_form_html() %}
+
+                                               <div class="row justify-content-center mb-6">
+                                                       <div class="col-12 col-sm-11 col-xl-12">
+                                                               <div class="row">
+                                                                       <div class="donation-card d-flex flex-column flex-md-row-reverse text-left col p-0">
+                                                                               <div class="card p-4 p-sm-6 p-md-4 pt-6">
+                                                                                       <div class="row py-md-3 px-md-6">
+                                                                                               <div class="col-12 col-lg-6 d-flex flex-column mb-6 mb-lg-0">
+                                                                                                       <h4 class="mb-5">Choose a currency</h4>
+                                                                                                       <div class="row pt-4">
+                                                                                                               <div class="col col-sm-4 col-md-5">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="currency" id="euro" value="euro" checked>
+                                                                                                                       <label for="euro" class="form-check-label radiobtn">€uro</label>
+                                                                                                               </div>
+                                                                                                               <div class="col col-sm-4 col-md-5">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="currency" id="usd" value="usd">
+                                                                                                                       <label for="usd" class="form-check-label radiobtn">USD $</label>
+                                                                                                               </div>
                                                                                                        </div>
                                                                                                </div>
-                                                                                       </div>
-                                                                                       
-                                                                                       <div class="col d-flex flex-column">
-                                                                                               <h4 class="mb-5">Frequency</h4>
-                                                                                               <div class="row pt-4">
-                                                                                                       <div class="col col-sm-4 col-md-5 col-lg-6">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="frequency" id="one-time-payment" value="single" checked>
-                                                                                                               <label for="one-time-payment" class="form-check-label radiobtn">One time</label>
-                                                                                                       </div>
-                                                                                                       <div class="col col-sm-4 col-md-5">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="frequency" id="monthly-payment" value="monthly">
-                                                                                                               <label for="monthly-payment" class="form-check-label radiobtn">Monthly</label>
+                                                                                               
+                                                                                               <div class="col d-flex flex-column">
+                                                                                                       <h4 class="mb-5">Frequency</h4>
+                                                                                                       <div class="row pt-4">
+                                                                                                               <div class="col col-sm-4 col-md-5 col-lg-6">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="frequency" id="one-time-payment" value="single" checked>
+                                                                                                                       <label for="one-time-payment" class="form-check-label radiobtn">One time</label>
+                                                                                                               </div>
+                                                                                                               <div class="col col-sm-4 col-md-5">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="frequency" id="monthly-payment" value="monthly">
+                                                                                                                       <label for="monthly-payment" class="form-check-label radiobtn">Monthly</label>
+                                                                                                               </div>
                                                                                                        </div>
                                                                                                </div>
                                                                                        </div>
-                                                                               </div>
-                                                                       
-                                                                               <div class="row mt-6">
-                                                                                       <div class="inline-card bg-blue-grey-50 col-11 mx-auto">
-                                                                                               <div class="or"></div>
-                                                                                               <div class="row mb-4 mb-sm-6 mb-lg-0">
-                                                                                                       <div class="col-12 col-lg-6 mb-6">
-                                                                                                               <h4 class="mb-5">Choose an amount</h4>
-                                                                                                               <div class="form-group d-flex flex-row flex-wrap" id="amount">
-                                                                                                                       <input class="amount-check" type="radio" name="amount" id="10" value="10" checked>
-                                                                                                                       <label for="10" class="form-check-label amount"><span id="amount_10">10</span><span class="currency">€</span></label>
-                                                                                                                       
-                                                                                                                       <input class="amount-check" type="radio" name="amount" id="25" value="25">
-                                                                                                                       <label for="25" class="form-check-label amount"><span id="amount_25">25</span><span class="currency">€</span></label>
-                                                                                                                       
-                                                                                                                       <input class="amount-check" type="radio" name="amount" id="50" value="50">
-                                                                                                                       <label for="50" class="form-check-label amount"><span id="amount_50">50</span><span class="currency">€</span></label>
-                                                                                                                       
-                                                                                                                       <input class="amount-check" type="radio" name="amount" id="75" value="50">
-                                                                                                                       <label for="50" class="form-check-label amount"><span id="amount_75">75</span><span class="currency">€</span></label>
-                                                                                                               
-                                                                                                                       <input class="amount-check" type="radio" name="amount" id="100" value="100">
-                                                                                                                       <label for="100" class="form-check-label amount"><span id="amount_100">100</span><span class="currency">€</span></label>
+                                                                               
+                                                                                       <div class="row mt-6">
+                                                                                               <div class="inline-card bg-blue-grey-50 col-11 mx-auto">
+                                                                                                       <div class="or"></div>
+                                                                                                       <div class="row mb-4 mb-sm-6 mb-lg-0">
+                                                                                                               <div class="col-12 col-lg-6 mb-6">
+                                                                                                                       <h4 class="mb-5">Choose an amount</h4>
+                                                                                                                       <div class="form-group d-flex flex-row flex-wrap" id="amount">
+                                                                                                                               <input class="amount-check" type="radio" name="amount" id="10" value="10" checked>
+                                                                                                                               <label for="10" class="form-check-label amount"><span id="amount_10">10</span><span class="currency">€</span></label>
+                                                                                                                               
+                                                                                                                               <input class="amount-check" type="radio" name="amount" id="25" value="25">
+                                                                                                                               <label for="25" class="form-check-label amount"><span id="amount_25">25</span><span class="currency">€</span></label>
+                                                                                                                               
+                                                                                                                               <input class="amount-check" type="radio" name="amount" id="50" value="50">
+                                                                                                                               <label for="50" class="form-check-label amount"><span id="amount_50">50</span><span class="currency">€</span></label>
+                                                                                                                               
+                                                                                                                               <input class="amount-check" type="radio" name="amount" id="75" value="50">
+                                                                                                                               <label for="50" class="form-check-label amount"><span id="amount_75">75</span><span class="currency">€</span></label>
                                                                                                                        
-                                                                                                                       <input class="amount-check" type="radio" name="amount" id="250" value="250">
-                                                                                                                       <label for="250" class="form-check-label amount"><span id="amount_250">250</span><span class="currency">€</span></label>
-                                                                                                               </div>                                                                                  
-                                                                                                       </div>
-                                                                                                       <div class="col">
-                                                                                                               <div class="form-group">
-                                                                                                                       <h4 class="mb-5">Enter your own</h4>
-                                                                                                                       <input type="number" class="ownamount w-100" id="enterYourOwn" placeholder="Enter your own amount">
+                                                                                                                               <input class="amount-check" type="radio" name="amount" id="100" value="100">
+                                                                                                                               <label for="100" class="form-check-label amount"><span id="amount_100">100</span><span class="currency">€</span></label>
+                                                                                                                               
+                                                                                                                               <input class="amount-check" type="radio" name="amount" id="250" value="250">
+                                                                                                                               <label for="250" class="form-check-label amount"><span id="amount_250">250</span><span class="currency">€</span></label>
+                                                                                                                       </div>                                                                                  
+                                                                                                               </div>
+                                                                                                               <div class="col">
+                                                                                                                       <div class="form-group">
+                                                                                                                               <h4 class="mb-5">Enter your own</h4>
+                                                                                                                               <input type="number" class="ownamount w-100" id="enterYourOwn" placeholder="Enter your own amount">
+                                                                                                                       </div>
                                                                                                                </div>
                                                                                                        </div>
-                                                                                               </div>
-                                                                                               <div class="row mt-5 mt-sm-6 mb-5 mb-lg-0 mt-lg-0">
-                                                                                                       <div class="col d-flex flex-row">
-                                                                                                               <h4 class="mr-3">Choose payment</h4>
-                                                                                                               <svg class="icon i_secure ml-4"><use xlink:href="#secure"/></svg>
-                                                                                                               <p class="text-uppercase blue_grey_300"><strong>Secure</strong></p>
-                                                                                                       </div>
-                                                                                               </div>
-                                                                                               
-                                                                                               <div class="row d-flex flex-column flex-lg-row pl-4 pr-4 md-4 mb-lg-0 mb-xl-6">
-                                                                                                       <div class="col col-lg-6 col-xl-4" id="ccpayment">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="payment" id="creditcard" value="creditcard" checked>
-                                                                                                               <label for="creditcard" class="form-check-label radiobtn cc">
-                                                                                                                       <picture>
-                                                                                                                               <source srcset="{{ static_url("img/amex.png") }},
-                                                                                                                                       {{ static_url("img/amex@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/amex@3x.png") }} 3x ">
-                                                                                                                               <img src="{{ static_url("img/amex.png") }}"
-                                                                                                                                        srcset="{{ static_url("img/amex.png") }},
-                                                                                                                                       {{ static_url("img/amex@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/amex@3x.png") }} 3x "
-                                                                                                                                       alt="Amex" class="m-xl-2">
-                                                                                                                       </picture>
-                                                                                                                       
-                                                                                                                       <picture>
-                                                                                                                               <source srcset="{{ static_url("img/mastercard.png") }},
-                                                                                                                                       {{ static_url("img/mastercard@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/mastercard@3x.png") }} 3x ">
-                                                                                                                               <img src="{{ static_url("img/mastercard.png") }}"
-                                                                                                                                        srcset="{{ static_url("img/mastercard.png") }},
-                                                                                                                                       {{ static_url("img/mastercard@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/mastercard@3x.png") }} 3x "
-                                                                                                                                       alt="Mastercard" class="m-xl-2">
-                                                                                                                       </picture>
-                                                                                                                       
-                                                                                                                       <picture>
-                                                                                                                               <source srcset="{{ static_url("img/visa.png") }},
-                                                                                                                                       {{ static_url("img/visa@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/visa@3x.png") }} 3x ">
-                                                                                                                               <img src="{{ static_url("img/visa.png") }}"
-                                                                                                                                        srcset="{{ static_url("img/visa.png") }},
-                                                                                                                                       {{ static_url("img/visa@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/visa@3x.png") }} 3x "
-                                                                                                                                       alt="Visa" class="m-xl-2">
-                                                                                                                       </picture>
-                                                                                                               </label>
-                                                                                                       </div>
-                                                                                                       
-                                                                                                       <div class="col col-lg-6 col-xl-4" id="sepapayment">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="payment" id="sepa-payment" value="sepa-payment">
-                                                                                                               <label for="sepa-payment" class="form-check-label radiobtn">SEPA direct debit</label>
+                                                                                                       <div class="row mt-5 mt-sm-6 mb-5 mb-lg-0 mt-lg-0">
+                                                                                                               <div class="col d-flex flex-row">
+                                                                                                                       <h4 class="mr-3">Choose payment</h4>
+                                                                                                                       <svg class="icon i_secure ml-4"><use xlink:href="#secure"/></svg>
+                                                                                                                       <p class="text-uppercase blue_grey_300"><strong>Secure</strong></p>
+                                                                                                               </div>
                                                                                                        </div>
                                                                                                        
-                                                                                                       <div class="col col-lg-6 col-xl-4" id="paymentpaypal">
-                                                                                                               <input class="form-check-input mr-4 radiobtn" type="radio" name="payment" id="paypal" value="paypal">
-                                                                                                               <label for="paypal" class="form-check-label radiobtn">
-                                                                                                                       <picture>
-                                                                                                                               <source srcset="{{ static_url("img/paypal.png") }},
-                                                                                                                                       {{ static_url("img/paypal@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/paypal@3x.png") }} 3x ">
-                                                                                                                               <img src="{{ static_url("img/paypal.png") }}"
-                                                                                                                                        srcset="{{ static_url("img/paypal.png") }},
-                                                                                                                                       {{ static_url("img/paypal@2x.png") }} 2x,
-                                                                                                                                       {{ static_url("img/paypal@3x.png") }} 3x "
-                                                                                                                                       alt="PayPal" class="m-xl-4">
-                                                                                                                       </picture>
-                                                                                                               </label>
+                                                                                                       <div class="row d-flex flex-column flex-lg-row pl-4 pr-4 md-4 mb-lg-0 mb-xl-6">
+                                                                                                               <div class="col col-lg-6 col-xl-4" id="ccpayment">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="payment" id="creditcard" value="creditcard" checked>
+                                                                                                                       <label for="creditcard" class="form-check-label radiobtn cc">
+                                                                                                                               <picture>
+                                                                                                                                       <source srcset="{{ static_url("img/amex.png") }},
+                                                                                                                                               {{ static_url("img/amex@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/amex@3x.png") }} 3x ">
+                                                                                                                                       <img src="{{ static_url("img/amex.png") }}"
+                                                                                                                                               srcset="{{ static_url("img/amex.png") }},
+                                                                                                                                               {{ static_url("img/amex@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/amex@3x.png") }} 3x "
+                                                                                                                                               alt="Amex" class="m-xl-2">
+                                                                                                                               </picture>
+                                                                                                                               
+                                                                                                                               <picture>
+                                                                                                                                       <source srcset="{{ static_url("img/mastercard.png") }},
+                                                                                                                                               {{ static_url("img/mastercard@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/mastercard@3x.png") }} 3x ">
+                                                                                                                                       <img src="{{ static_url("img/mastercard.png") }}"
+                                                                                                                                               srcset="{{ static_url("img/mastercard.png") }},
+                                                                                                                                               {{ static_url("img/mastercard@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/mastercard@3x.png") }} 3x "
+                                                                                                                                               alt="Mastercard" class="m-xl-2">
+                                                                                                                               </picture>
+                                                                                                                               
+                                                                                                                               <picture>
+                                                                                                                                       <source srcset="{{ static_url("img/visa.png") }},
+                                                                                                                                               {{ static_url("img/visa@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/visa@3x.png") }} 3x ">
+                                                                                                                                       <img src="{{ static_url("img/visa.png") }}"
+                                                                                                                                               srcset="{{ static_url("img/visa.png") }},
+                                                                                                                                               {{ static_url("img/visa@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/visa@3x.png") }} 3x "
+                                                                                                                                               alt="Visa" class="m-xl-2">
+                                                                                                                               </picture>
+                                                                                                                       </label>
+                                                                                                               </div>
+                                                                                                               
+                                                                                                               <div class="col col-lg-6 col-xl-4" id="sepapayment">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="payment" id="sepa-payment" value="sepa-payment">
+                                                                                                                       <label for="sepa-payment" class="form-check-label radiobtn">SEPA direct debit</label>
+                                                                                                               </div>
+                                                                                                               
+                                                                                                               <div class="col col-lg-6 col-xl-4" id="paymentpaypal">
+                                                                                                                       <input class="form-check-input mr-4 radiobtn" type="radio" name="payment" id="paypal" value="paypal">
+                                                                                                                       <label for="paypal" class="form-check-label radiobtn">
+                                                                                                                               <picture>
+                                                                                                                                       <source srcset="{{ static_url("img/paypal.png") }},
+                                                                                                                                               {{ static_url("img/paypal@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/paypal@3x.png") }} 3x ">
+                                                                                                                                       <img src="{{ static_url("img/paypal.png") }}"
+                                                                                                                                               srcset="{{ static_url("img/paypal.png") }},
+                                                                                                                                               {{ static_url("img/paypal@2x.png") }} 2x,
+                                                                                                                                               {{ static_url("img/paypal@3x.png") }} 3x "
+                                                                                                                                               alt="PayPal" class="m-xl-4">
+                                                                                                                               </picture>
+                                                                                                                       </label>
+                                                                                                               </div>
                                                                                                        </div>
                                                                                                </div>
                                                                                        </div>
-                                                                               </div>
+                                                                                       
+                                                                                       <input type="submit" class="btn btn-primary btn-lg m-0" style="position: relative; top: -24px; left: 50%; transform: translateX(-50%);" value="Donate Now">
                                                                                
-                                                                               <button type="button" class="btn btn-primary btn-lg m-0" style="position: relative; top: -24px; left: 50%; transform: translateX(-50%);">Donate Now</button>
-                                                                       
-                                                                               <p class="small text-left mt-5 mb-6">
-                                                                                       There should also be some area for the small-print since we need to tell people who they are donating to and that we don't do any refunds, etc.
-                                                                               </p>
-                                                                       </div>
-                                                                       
-                                                                       <div class="info col-md-4 bg-blue-grey-900 text-white p-5 pt-6">
-                                                                               <div class="mb-6">
-                                                                                       <h3>IP<strong>Fire</strong> is an Open Source software project.</h3>
-
-                                                                                       <p class="copy">
-                                                                                               IPFire is an Open Source software project.
+                                                                                       <p class="small text-left mt-5 mb-6">
+                                                                                               There should also be some area for the small-print since we need to tell people who they are donating to and that we don't do any refunds, etc.
                                                                                        </p>
-                                                               
-                                                                                       <p class="copy">
-                                                                                               Development and keeping the project healthy is carried out by a
-                                                                                               group of volunteers who have built a very successful product,
-                                                                                               which hundreds of thousands of people use every day.
-                                                                                       </p>
-                                                               
-                                                                                       <p class="copy">
-                                                                                               Your donation helps us to make IPFire even better...
-                                                                                       </p>
-                                                                               </div>
-                                                                                       
-                                                                               <div class="mb-6 d-flex justify-content-between">                                                                               
-                                                                                       <h3><a href="#whydonate">Why should I donate?</a></h3><a href="#whydonate"><svg class="icon i_arrow_down_2 ml-4"><use xlink:href="#arrow-down-2"/></svg></a>
                                                                                </div>
+                                                                               
+                                                                               <div class="info col-md-4 bg-blue-grey-900 text-white p-5 pt-6">
+                                                                                       <div class="mb-6">
+                                                                                               <h3>IP<strong>Fire</strong> is an Open Source software project.</h3>
+
+                                                                                               <p class="copy">
+                                                                                                       IPFire is an Open Source software project.
+                                                                                               </p>
+                                                                       
+                                                                                               <p class="copy">
+                                                                                                       Development and keeping the project healthy is carried out by a
+                                                                                                       group of volunteers who have built a very successful product,
+                                                                                                       which hundreds of thousands of people use every day.
+                                                                                               </p>
                                                                        
-                                                                               <div class="mb-6 d-flex justify-content-between">
-                                                                                       <h3><a href="#howmuch">How much should I give?</a></h3><a href="#howmuch"><svg class="icon i_arrow_down_2 ml-4"><use xlink:href="#arrow-down-2"/></svg></a>
+                                                                                               <p class="copy">
+                                                                                                       Your donation helps us to make IPFire even better...
+                                                                                               </p>
+                                                                                       </div>
+                                                                                               
+                                                                                       <div class="mb-6 d-flex justify-content-between">                                                                               
+                                                                                               <h3><a href="#whydonate">Why should I donate?</a></h3><a href="#whydonate"><svg class="icon i_arrow_down_2 ml-4"><use xlink:href="#arrow-down-2"/></svg></a>
+                                                                                       </div>
+                                                                               
+                                                                                       <div class="mb-6 d-flex justify-content-between">
+                                                                                               <h3><a href="#howmuch">How much should I give?</a></h3><a href="#howmuch"><svg class="icon i_arrow_down_2 ml-4"><use xlink:href="#arrow-down-2"/></svg></a>
+                                                                                       </div>
                                                                                </div>
                                                                        </div>
                                                                </div>
                                                        </div>
                                                </div>
-                                       </div>
+                                       </form>
                                </section>
                        </div>
                </div>
index 1474e98..2497f4d 100644 (file)
@@ -18,6 +18,8 @@ import releases
 import settings
 import talk
 
+from . import zeiterfassung
+
 class Backend(object):
        def __init__(self, configfile, debug=False):
                # Read configuration file.
@@ -46,6 +48,8 @@ class Backend(object):
                self.releases = releases.Releases(self)
                self.talk = talk.Talk(self)
 
+               self.zeiterfassung = zeiterfassung.ZeiterfassungClient(self)
+
        def read_config(self, configfile):
                cp = configparser.ConfigParser()
                cp.read(configfile)
diff --git a/webapp/backend/zeiterfassung.py b/webapp/backend/zeiterfassung.py
new file mode 100644 (file)
index 0000000..626b365
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+import hashlib
+import hmac
+import json
+import tornado.httpclient
+import tornado.gen
+import urllib
+import urlparse
+
+from misc import Object
+
+class ZeiterfassungClient(Object):
+       algorithm = "Zeiterfassung-HMAC-SHA512"
+
+       def init(self):
+               self.url = self.settings.get("zeiterfassung_url")
+
+               # API credentials
+               self.api_key    = self.settings.get("zeiterfassung_api_key")
+               self.api_secret = self.settings.get("zeiterfassung_api_secret")
+
+               # Check if all configuration values are set
+               if not all((self.url, self.api_key, self.api_secret)):
+                       raise RuntimeError("%s is not configured" % self.__class__.__name__)
+
+               # Create HTTPClient
+               self.http_client = tornado.httpclient.AsyncHTTPClient(
+                       defaults = {
+                               "User-Agent" : "IPFireWebApp",
+                       }
+               )
+
+       def _make_signature(self, method, path, body):
+               # Empty since we only support POST
+               canonical_query = ""
+
+               # Put everything together
+               string_to_sign = "\n".join((
+                       method, path, canonical_query,
+               )).encode("utf-8") + body
+
+               # Compute HMAC
+               h = hmac.new(self.api_secret.encode("utf-8"), string_to_sign, hashlib.sha512)
+
+               return h.hexdigest()
+
+       @tornado.gen.coroutine
+       def send_request(self, path, **kwargs):
+               url = urlparse.urljoin(self.url, path)
+
+               # Query arguments are all keyword arguments
+               arguments = kwargs
+
+               request = tornado.httpclient.HTTPRequest(url, method="POST")
+               request.body = urllib.urlencode(arguments)
+
+               # Compose the signature
+               signature = self._make_signature("POST", path, request.body)
+
+               # Add authorization header
+               request.headers["Authorization"] = " ".join(
+                       (self.algorithm, self.api_key, signature)
+               )
+
+               # Send the request
+               response = yield self.http_client.fetch(request)
+
+               # Decode the JSON response
+               d = json.loads(response.body.decode())
+
+               raise tornado.gen.Return(d)
index bfadf61..d380d5f 100644 (file)
@@ -11,6 +11,7 @@ import os
 #import time
 #import tornado.database
 #import tornado.locale
+import tornado.gen
 import tornado.web
 #import unicodedata
 
@@ -122,6 +123,44 @@ class DonateHandler(BaseHandler):
        def get(self):
                self.render("donate.html")
 
+       @tornado.gen.coroutine
+       def post(self):
+               # Get form inputs
+               args = {
+                       "amount"       : self.get_argument("amount"),
+                       "currency"     : self.get_argument("currency", "EUR"),
+                       "method"       : self.get_argument("method", None),
+
+                       # Is this a recurring donation?
+                       "recurring"    : self.get_argument("frequency") == "monthly",
+
+                       # XXX Missing inputs
+                       "email"        : "john.doe@example.com",
+                       "first_name"   : "John",
+                       "last_name"    : "Doe",
+                       "street1"      : "Street 1",
+                       "street2"      : "Street 2",
+                       "post_code"    : "POST CODE",
+                       "city"         : "City",
+                       "state"        : "State",
+                       "country_code" : "DE",
+               }
+
+               # Send request to Zeiterfassung
+               try:
+                       response = yield self.backend.zeiterfassung.send_request(
+                               "/api/v1/donations/create/ipfire-project", **args)
+
+               except Exception:
+                       raise # XXX handle any problems when Zeiterfassung is unreachable
+
+               # Redirect the user to the payment page
+               redirect_url = response.get("redirect_url")
+               if not redirect_url:
+                       raise tornado.web.HTTPError(500, "Did not receive a redirect URL")
+
+               self.redirect(redirect_url)
+
 
 class DownloadHandler(BaseHandler):
        def get(self):