Browse Source

feat(webapp): adds donation form

Nils Wisiol 5 years ago
parent
commit
29e3c187fe

+ 1 - 1
api/desecapi/models.py

@@ -323,7 +323,7 @@ class Donation(models.Model):
     created = models.DateTimeField(default=get_default_value_created)
     created = models.DateTimeField(default=get_default_value_created)
     name = models.CharField(max_length=255)
     name = models.CharField(max_length=255)
     iban = models.CharField(max_length=34)
     iban = models.CharField(max_length=34)
-    bic = models.CharField(max_length=11)
+    bic = models.CharField(max_length=11, blank=True)
     amount = models.DecimalField(max_digits=8, decimal_places=2)
     amount = models.DecimalField(max_digits=8, decimal_places=2)
     message = models.CharField(max_length=255, blank=True)
     message = models.CharField(max_length=255, blank=True)
     due = models.DateTimeField(default=get_default_value_due)
     due = models.DateTimeField(default=get_default_value_due)

+ 3 - 1
api/desecapi/serializers.py

@@ -497,7 +497,9 @@ class DonationSerializer(serializers.ModelSerializer):
 
 
     class Meta:
     class Meta:
         model = models.Donation
         model = models.Donation
-        fields = ('name', 'iban', 'bic', 'amount', 'message', 'email')
+        fields = ('name', 'iban', 'bic', 'amount', 'message', 'email', 'mref')
+        read_only_fields = ('mref',)
+
 
 
     @staticmethod
     @staticmethod
     def validate_bic(value):
     def validate_bic(value):

+ 0 - 10
api/desecapi/templates/emails/donation/donor-content.txt

@@ -16,13 +16,3 @@ Again, thank you so much.
 
 
 Cheers,
 Cheers,
 Nils
 Nils
-
---
-deSEC
-Kyffhäuserstr. 5
-10781 Berlin
-Germany
-
-phone: +49-30-47384344
-
-Vorstandsvorsitzender: Nils Wisiol

+ 2 - 0
docker-compose.dev.yml

@@ -64,6 +64,8 @@ services:
     command: bash -c "cat src/env.js.template | envsubst > src/env.js && npm run serve --fix"
     command: bash -c "cat src/env.js.template | envsubst > src/env.js && npm run serve --fix"
     environment:
     environment:
     - DESECSTACK_DOMAIN
     - DESECSTACK_DOMAIN
+    - DESECSTACK_API_SEPA_CREDITOR_ID
+    - DESECSTACK_API_SEPA_CREDITOR_NAME
     - HOST=0.0.0.0
     - HOST=0.0.0.0
     - PORT=443
     - PORT=443
     networks:
     networks:

+ 2 - 0
docker-compose.yml

@@ -185,6 +185,8 @@ services:
     build: webapp
     build: webapp
     environment:
     environment:
     - DESECSTACK_DOMAIN
     - DESECSTACK_DOMAIN
+    - DESECSTACK_API_SEPA_CREDITOR_ID
+    - DESECSTACK_API_SEPA_CREDITOR_NAME
     volumes:
     volumes:
     - ./webapp/:/usr/src/app/
     - ./webapp/:/usr/src/app/
     - webapp_dist:/usr/src/app/dist
     - webapp_dist:/usr/src/app/dist

+ 1 - 1
webapp/package.json

@@ -10,7 +10,7 @@
     "lint": "vue-cli-service lint"
     "lint": "vue-cli-service lint"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@mdi/font": "^3.6.95",
+    "@mdi/font": "^4.5.95",
     "axios": "^0.19.0",
     "axios": "^0.19.0",
     "core-js": "^3.3.2",
     "core-js": "^3.3.2",
     "roboto-fontface": "*",
     "roboto-fontface": "*",

+ 206 - 0
webapp/src/components/DonateDirectDebitForm.vue

@@ -0,0 +1,206 @@
+<template>
+  <div>
+    <v-alert v-if="done" type="success">
+      <p>
+        We hereby confirm your donation to deSEC. We would like to <b>thank you</b> for
+        your support. If you have any questions concerning your donation, how
+        we use your money, or if we can do anything else for you: Please do not
+        hesitate to contact us anytime.
+      </p>
+      <p>
+        We will debit {{ amount }} € from your account within the next
+        two weeks. Your mandate reference number is {{ mref }}; our
+        creditor identifier is {{ creditorid }}.
+      </p>
+      <p>
+        Please note that the payment is handled by {{ creditorname }}, which
+        may be the name appearing on your bank statement.
+      </p>
+      <p>Again, thank you so much.</p>
+      <v-btn flat depressed outlined block :to="{name: 'home'}">Done</v-btn>
+    </v-alert>
+    <v-form v-if="!done" @submit.prevent="donate" ref="form">
+      <v-alert :value="!!(errors && errors.length)" type="error">
+        <div v-if="errors.length > 1">
+          <li v-for="error of errors" :key="error.message" >
+            <b>{{ error.message }}</b>
+            {{ error }}
+          </li>
+        </div>
+        <div v-else>
+          {{ errors[0] }}
+        </div>
+      </v-alert>
+
+      <v-text-field
+              v-model="name"
+              label="Full Name of the Account Holder"
+              prepend-icon="mdi-account"
+              outline
+              required
+              :disabled="working"
+              :rules="name_rules"
+              :error-messages="name_errors"
+      />
+
+      <v-text-field
+              v-model="iban"
+              label="IBAN"
+              prepend-icon="mdi-bank"
+              outline
+              required
+              :disabled="working"
+              :rules="iban_rules"
+              :error-messages="iban_errors"
+              validate-on-blur
+      />
+
+      <v-text-field
+              v-model="amount"
+              label="Amount in Euros"
+              prepend-icon="mdi-cash-100"
+              outline
+              required
+              :disabled="working"
+              :rules="amount_rules"
+              :error-messages="amount_errors"
+      />
+
+      <v-text-field
+              v-model="message"
+              label="Message (optional)"
+              prepend-icon="mdi-message-text-outline"
+              outline
+              :disabled="working"
+              validate-on-blur
+      />
+
+      <v-text-field
+              v-model="email"
+              label="Email Address (optional)"
+              prepend-icon="mdi-email"
+              outline
+              :disabled="working"
+              :rules="email_rules"
+              :error-messages="email_errors"
+              validate-on-blur
+      />
+
+      <v-btn
+              depressed
+              block
+              color="primary"
+              type="submit"
+              :disabled="working"
+              :loading="working"
+      >Donate Now</v-btn>
+    </v-form>
+  </div>
+</template>
+
+<script>
+  import axios from 'axios';
+  import {email_pattern} from '../validation';
+  import {DESECSTACK_API_SEPA_CREDITOR_ID, DESECSTACK_API_SEPA_CREDITOR_NAME} from "../env";
+
+  const HTTP = axios.create({
+    baseURL: '/api/v1/',
+    headers: {
+    },
+  });
+
+  export default {
+    name: 'SignUp',
+    data: () => ({
+      valid: false,
+      working: false,
+      done: false,
+      errors: [],
+
+      /* from env */
+      creditorid: DESECSTACK_API_SEPA_CREDITOR_ID,
+      creditorname: DESECSTACK_API_SEPA_CREDITOR_NAME,
+
+      /* account holder name field */
+      name: '',
+      name_rules: [v => !!v || 'We need the account holder\'s name to debit an account.'],
+      name_errors: [],
+
+      /* IBAN field */
+      iban: '',
+      iban_rules: [v => !!v || 'For direct debit, an IBAN is required. If you do not have an IBAN, please consider using alternative donation methods.'],
+      iban_errors: [],
+
+      /* amount field */
+      amount: 10,
+      amount_rules: [
+              v => !!v || 'Please specify the amount you want to donate, in Euros.',
+              v => !isNaN(v) || 'Please specify the amount as a decimal number.'
+      ],
+      amount_errors: [],
+
+      /* message field */
+      message: '',
+
+      /* email field */
+      email: '',
+      email_rules: [v => v === '' || !!email_pattern.test(v || '') || 'This is not an email address.'],
+      email_errors: [],
+
+      /* sent by server */
+      mref: '',
+    }),
+    methods: {
+      async reset() {
+        this.$refs.form.reset();
+      },
+      async donate() {
+        if (!this.$refs.form.validate()) {
+          return;
+        }
+        this.working = true;
+        this.errors = [];
+        try {
+          let response = await HTTP.post('donation/', {
+            amount: this.amount,
+            name: this.name,
+            iban: this.iban,
+            bic: "",
+            message: this.message,
+            email: this.email,
+          });
+          this.mref = response.data.mref;
+          this.done = true;
+        } catch (error) {
+          if (error.response) {
+            // status is not 2xx
+            if (error.response.status < 500 && typeof error.response.data === 'object') {
+              // 3xx or 4xx
+              let extracted = false;
+              if ('email' in error.response.data) {
+                this.email_errors = [error.response.data.email[0]];
+                extracted = true;
+              }
+              if ('amount' in error.response.data) {
+                this.amount_errors = [error.response.data.amount[0]];
+                extracted = true;
+              }
+              // TODO extract more errors
+              if (!extracted) {
+                this.errors = [error.response];
+              }
+            } else {
+              // 5xx
+              this.errors = ['Something went wrong at the server, but we currently do not know why. The customer support was already notified.'];
+            }
+          } else if (error.request) {
+            this.errors = ['Cannot contact our servers. Are you offline?'];
+          } else {
+            this.errors = [error.message];
+          }
+        }
+        this.working = false;
+      },
+    },
+  };
+</script>

+ 3 - 1
webapp/src/env.js.template

@@ -1,3 +1,5 @@
 export const DESECSTACK_DOMAIN = '${DESECSTACK_DOMAIN}';
 export const DESECSTACK_DOMAIN = '${DESECSTACK_DOMAIN}';
 export const LOCAL_PUBLIC_SUFFIXES = ['dedyn.${DESECSTACK_DOMAIN}'];
 export const LOCAL_PUBLIC_SUFFIXES = ['dedyn.${DESECSTACK_DOMAIN}'];
-export const EMAIL = atob(atob('YzNWd2NHOXlkRUJrWlhObFl5NXBidz09'));
+export const EMAIL = atob(atob('YzNWd2NHOXlkRUJrWlhObFl5NXBidz09'));
+export const DESECSTACK_API_SEPA_CREDITOR_ID = '${DESECSTACK_API_SEPA_CREDITOR_ID}';
+export const DESECSTACK_API_SEPA_CREDITOR_NAME = '${DESECSTACK_API_SEPA_CREDITOR_NAME}';

+ 133 - 52
webapp/src/views/Donate.vue

@@ -1,79 +1,149 @@
 <template>
 <template>
   <v-container>
   <v-container>
-    <h1>Donate to deSEC</h1>
-    <h2>You like deSEC? Donate now to support us in our mission. Your donation shows us we're on the right track.</h2>
+    <h1>Donate now to support our mission</h1>
+    <h2>Like our community service? Your donation shows us we're on the right track.</h2>
     <v-row>
     <v-row>
-      <v-col col="12" lg="4">
+      <v-col cols="12" md="6">
         <v-card>
         <v-card>
           <v-toolbar
           <v-toolbar
                   color="primary"
                   color="primary"
                   dark
                   dark
                   flat
                   flat
           >
           >
-            <v-toolbar-title>Support deSEC's quest to make the Internet more secure!</v-toolbar-title>
+            <v-toolbar-title>Donate</v-toolbar-title>
           </v-toolbar>
           </v-toolbar>
           <v-card-text>
           <v-card-text>
+            <v-expansion-panels class="mb-4" focusable>
+              <v-expansion-panel>
+                <v-expansion-panel-header class="subtitle-1">
+                  <v-layout>
+                    <v-icon class="mr-2">mdi-bank-transfer-in</v-icon> Let us Take your Money: Direct Debit (Europe)
+                  </v-layout>
+                </v-expansion-panel-header>
+                <v-expansion-panel-content class="pt-4">
+                  <p>
+                    With your permission, we debit your donation directly from your European bank account.
+                    To give us permission, use this form:
+                  </p>
+                  <DonateDirectDebitForm/>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+              <v-expansion-panel>
+                <v-expansion-panel-header class="subtitle-1">
+                  <v-layout>
+                    <v-icon class="mr-2">mdi-bank-transfer-out</v-icon> Send us Money: Bank Transfer (Europe)
+                  </v-layout>
+                </v-expansion-panel-header>
+                <v-expansion-panel-content class="pt-4">
+                  <p>
+                    We're happy to accept donations via bank transfer. Please use the following account details:
+                  </p>
+                  <v-simple-table>
+                    <tbody>
+                    <tr>
+                      <td>Recipient</td>
+                      <td>deSEC e.V.</td>
+                    </tr>
+                    <tr>
+                      <td>IBAN</td>
+                      <td>DE91 8306 5408 0004 1580 59</td>
+                    </tr>
+                    <tr>
+                      <td>BIC</td>
+                      <td>GENODEF1SLR</td>
+                    </tr>
+                    </tbody>
+                  </v-simple-table>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+              <v-expansion-panel>
+                <v-expansion-panel-header class="subtitle-1">
+                  <v-layout>
+                    <v-icon class="mr-2">mdi-credit-card-outline</v-icon> Credit Card
+                  </v-layout>
+                </v-expansion-panel-header>
+                <v-expansion-panel-content class="pt-4">
+                  <p>
+                    To donate by credit card, <strong>please use <a href="https://liberapay.com/deSEC/donate">our
+                    account at Liberapay</a></strong>.
+                  </p>
+                  <p>
+                    By default, Liberapay sets up a recurring donation. If you want to support us only once, simply stop
+                    the automatic payment plan right after your first donation. However, as our costs are recurring, we
+                    actually do appreciate recurring donations.
+                  </p>
+                  <p>
+                    Are you based in Europe? You almost certainly can perform a donation via direct debit or bank
+                    transfer above (you just need your IBAN). With these payment methods, the fees subtracted from your
+                    donation will be much less, and we will receive more of your money! If you want to support us
+                    regularly, you can also set up a recurring direct debit donation through Liberapay.
+                  </p>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+              <v-expansion-panel>
+                <v-expansion-panel-header class="subtitle-1">
+                  <v-layout>
+                    <v-icon class="mr-2">mdi-paypal</v-icon> PayPal
+                  </v-layout>
+                </v-expansion-panel-header>
+                <v-expansion-panel-content class="pt-4">
+                  <p>
+                    To donate via PayPal, <strong>please use <a href="https://liberapay.com/deSEC/donate">our account at
+                    Liberapay</a></strong>. Note that PayPal charges us the highest fees of all, so if you can use one
+                    of the other donation methods, that would be appreciated!
+                  </p>
+                  <p>
+                    By default, Liberapay sets up a recurring donation. If you want to support us only once, simply stop
+                    the automatic payment plan right after your first donation. However, as our costs are recurring, we
+                    actually do appreciate recurring donations.
+                  </p>
+                  <p>
+                    Are you based in Europe? You almost certainly can perform a donation via direct debit or bank
+                    transfer above (you just need your IBAN). With these payment methods, the fees subtracted from your
+                    donation will be much less, and we will receive more of your money! If you want to support us
+                    regularly, you can also set up a recurring direct debit donation through Liberapay.
+                  </p>
+                </v-expansion-panel-content>
+              </v-expansion-panel>
+            </v-expansion-panels>
+            <div class="title">Donation Receipts</div>
             <p>
             <p>
-              deSEC is dedicated to enhance the security of data transmission via the Internet, by introducing
-              state-of-the art encryption technology. Sensitive client data is stored only in Germany, and safely
-              protected from unauthorized access by criminals or government agencies. Your donation is used to improve
-              our technical infrastructure for our free dynDNS service and ensures its smooth operation.
+              deSEC e.V. is registered as charity organization in Germany. If you pay taxes here, you can deduct your
+              donation from your taxes, and we can provide your with a donation receipt for that purpose. Note that for
+              donations below 200 €, no receipt is needed to claim the tax deduction.
             </p>
             </p>
-            <p>
-              Your donation gives you a way to say "Thanks!". It also supports the future developments of our services
-              which make the Internet more secure. If you would like to contribute to this, or if you are simpliy
-              excited about our free dynDNS service, please support us with your donation and encourage others to do
-              alike!
-            </p>
-            <p>
-              deSEC e.V. is registered as charity organization, so if you pay taxes in Germany, you may be able to use
-              your donation in your tax declaration. We automatically issue donations receipts for donations over 200€;
-              for donations below that the receipt is not needed to claim the tax deduction.
-            </p>
-          </v-card-text>
-        </v-card>
-      </v-col>
-      <v-col cols="12" md="6" lg="4">
-        <v-card>
-          <v-toolbar
-                  color="primary"
-                  dark
-                  flat
-          >
-            <v-toolbar-title>Donate via Bank Transfer (SEPA)</v-toolbar-title>
-          </v-toolbar>
-          <v-card-text>
-            <p>We happily accept donations via bank transfer. Please use the following account details.</p>
-            <v-simple-table>
-              <tbody>
-              <tr>
-                <td>Recipient</td>
-                <td class="fixed-width">deSEC e.V.</td>
-              </tr>
-              <tr>
-                <td>IBAN</td>
-                <td class="fixed-width">DE91 8306 5408 0004 1580 59</td>
-              </tr>
-              <tr>
-                <td>BIC</td>
-                <td class="fixed-width">GENODEF1SLR</td>
-              </tr>
-              </tbody>
-            </v-simple-table>
           </v-card-text>
           </v-card-text>
         </v-card>
         </v-card>
       </v-col>
       </v-col>
-      <v-col cols="12" md="6" lg="4">
+      <v-col col="12" md="6">
         <v-card>
         <v-card>
           <v-toolbar
           <v-toolbar
                   color="primary"
                   color="primary"
                   dark
                   dark
                   flat
                   flat
           >
           >
-            <v-toolbar-title>Donate in Some Other Way</v-toolbar-title>
+            <v-toolbar-title>Support our Quest</v-toolbar-title>
           </v-toolbar>
           </v-toolbar>
           <v-card-text>
           <v-card-text>
-            <p></p>
+            <p>
+              deSEC is dedicated to enhance the security of online data transmission, by spreading the seamless use of
+              state-of-the art encryption technology. Sensitive data is stored in Germany only, safely protected from
+              unauthorized access by criminals or government agencies.
+            </p>
+            <p>
+              Operating our free DNS service reliably incurs significant cost (several thousand euros each month!),
+              mostly for the serious technical infrastructure that is required. Your donation is used to cover these
+              expenses and ensures our service's smooth operation.
+            </p>
+            <p>
+              We also need your donation to support the future development of our services to make the Internet more
+              secure. If you would like to contribute to this, please support us with your donation and encourage
+              others to do alike.
+            </p>
+            <p>
+              Your donation also gives you a way to say “Thanks!”. If you are excited about our free community service,
+              please consider expressing your gratitude with a small (or large) gift.
+            </p>
           </v-card-text>
           </v-card-text>
         </v-card>
         </v-card>
       </v-col>
       </v-col>
@@ -81,6 +151,17 @@
   </v-container>
   </v-container>
 </template>
 </template>
 
 
+<script>
+  import DonateDirectDebitForm from '@/components/DonateDirectDebitForm.vue';
+
+  export default {
+    name: 'Donate',
+    components: {
+      DonateDirectDebitForm,
+    }
+  }
+</script>
+
 <style lang="scss">
 <style lang="scss">
   .fixed-width {
   .fixed-width {
     font-family: monospace;
     font-family: monospace;