From 44ebb9287475279833a33a27b7eea8aae2d389c1 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Sun, 6 May 2018 12:50:53 +0200
Subject: [PATCH] See #187: Front logic for password reset and email
 confirmation

---
 .../email/email_confirmation_message.txt      |  8 +++
 api/funkwhale_api/users/adapters.py           |  7 +-
 front/src/router/index.js                     |  9 +++
 front/src/views/auth/EmailConfirm.vue         | 71 +++++++++++++++++++
 front/src/views/auth/PasswordReset.vue        |  2 +-
 front/src/views/auth/PasswordResetConfirm.vue |  2 +-
 6 files changed, 96 insertions(+), 3 deletions(-)
 create mode 100644 api/funkwhale_api/templates/account/email/email_confirmation_message.txt
 create mode 100644 front/src/views/auth/EmailConfirm.vue

diff --git a/api/funkwhale_api/templates/account/email/email_confirmation_message.txt b/api/funkwhale_api/templates/account/email/email_confirmation_message.txt
new file mode 100644
index 00000000..8aec540f
--- /dev/null
+++ b/api/funkwhale_api/templates/account/email/email_confirmation_message.txt
@@ -0,0 +1,8 @@
+{% load account %}{% user_display user as user_display %}{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Hello from {{ site_name }}!
+
+You're receiving this e-mail because user {{ user_display }} at {{ site_domain }} has given yours as an e-mail address to connect their account.
+
+To confirm this is correct, go to {{ funkwhale_url }}/auth/email/confirm?key={{ key }}
+{% endblocktrans %}{% endautoescape %}
+{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you from {{ site_name }}!
+{{ site_domain }}{% endblocktrans %}
diff --git a/api/funkwhale_api/users/adapters.py b/api/funkwhale_api/users/adapters.py
index 96d1b8b1..7bd341d1 100644
--- a/api/funkwhale_api/users/adapters.py
+++ b/api/funkwhale_api/users/adapters.py
@@ -1,5 +1,6 @@
-from allauth.account.adapter import DefaultAccountAdapter
+from django.conf import settings
 
+from allauth.account.adapter import DefaultAccountAdapter
 from dynamic_preferences.registries import global_preferences_registry
 
 
@@ -8,3 +9,7 @@ class FunkwhaleAccountAdapter(DefaultAccountAdapter):
     def is_open_for_signup(self, request):
         manager = global_preferences_registry.manager()
         return manager['users__registration_enabled']
+
+    def send_mail(self, template_prefix, email, context):
+        context['funkwhale_url'] = settings.FUNKWHALE_URL
+        return super().send_mail(template_prefix, email, context)
diff --git a/front/src/router/index.js b/front/src/router/index.js
index 3bad260b..b1e20802 100644
--- a/front/src/router/index.js
+++ b/front/src/router/index.js
@@ -11,6 +11,7 @@ import Settings from '@/components/auth/Settings'
 import Logout from '@/components/auth/Logout'
 import PasswordReset from '@/views/auth/PasswordReset'
 import PasswordResetConfirm from '@/views/auth/PasswordResetConfirm'
+import EmailConfirm from '@/views/auth/EmailConfirm'
 import Library from '@/components/library/Library'
 import LibraryHome from '@/components/library/Home'
 import LibraryArtist from '@/components/library/Artist'
@@ -69,6 +70,14 @@ export default new Router({
         defaultEmail: route.query.email
       })
     },
+    {
+      path: '/auth/email/confirm',
+      name: 'auth.email-confirm',
+      component: EmailConfirm,
+      props: (route) => ({
+        defaultKey: route.query.key
+      })
+    },
     {
       path: '/auth/password/reset/confirm',
       name: 'auth.password-reset-confirm',
diff --git a/front/src/views/auth/EmailConfirm.vue b/front/src/views/auth/EmailConfirm.vue
new file mode 100644
index 00000000..7ffa3c8d
--- /dev/null
+++ b/front/src/views/auth/EmailConfirm.vue
@@ -0,0 +1,71 @@
+<template>
+  <div class="main pusher" v-title="$t('Confirm your email')">
+    <div class="ui vertical stripe segment">
+      <div class="ui small text container">
+        <h2>{{ $t('Confirm your email') }}</h2>
+        <form v-if="!success" class="ui form" @submit.prevent="submit()">
+          <div v-if="errors.length > 0" class="ui negative message">
+            <div class="header">{{ $t('Error while confirming your email') }}</div>
+            <ul class="list">
+              <li v-for="error in errors">{{ error }}</li>
+            </ul>
+          </div>
+          <div class="field">
+            <label>{{ $t('Confirmation code') }}</label>
+            <input type="text" required v-model="key" />
+          </div>
+          <router-link :to="{path: '/login'}">
+            {{ $t('Back to login') }}
+          </router-link>
+          <button :class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']" type="submit">
+            {{ $t('Confirm your email') }}</button>
+        </form>
+        <div v-else class="ui positive message">
+          <div class="header">{{ $t('Email confirmed') }}</div>
+          <p>{{ $t('Your email address was confirmed, you can now use the service without limitations.') }}</p>
+          <router-link :to="{name: 'login'}">
+            {{ $t('Proceed to login') }}
+          </router-link>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import axios from 'axios'
+
+export default {
+  props: ['defaultKey'],
+  data () {
+    return {
+      isLoading: false,
+      errors: [],
+      key: this.defaultKey,
+      success: false
+    }
+  },
+  methods: {
+    submit () {
+      let self = this
+      self.isLoading = true
+      self.errors = []
+      let payload = {
+        key: this.key
+      }
+      return axios.post('auth/registration/verify-email/', payload).then(response => {
+        self.isLoading = false
+        self.success = true
+      }, error => {
+        self.errors = error.backendErrors
+        self.isLoading = false
+      })
+    }
+  }
+
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+</style>
diff --git a/front/src/views/auth/PasswordReset.vue b/front/src/views/auth/PasswordReset.vue
index 6e80661b..f6b445e0 100644
--- a/front/src/views/auth/PasswordReset.vue
+++ b/front/src/views/auth/PasswordReset.vue
@@ -5,7 +5,7 @@
         <h2>{{ $t('Reset your password') }}</h2>
         <form class="ui form" @submit.prevent="submit()">
           <div v-if="errors.length > 0" class="ui negative message">
-            <div class="header">{{ $('Error while asking for a password reset') }}</div>
+            <div class="header">{{ $t('Error while asking for a password reset') }}</div>
             <ul class="list">
               <li v-for="error in errors">{{ error }}</li>
             </ul>
diff --git a/front/src/views/auth/PasswordResetConfirm.vue b/front/src/views/auth/PasswordResetConfirm.vue
index d2919249..102ed612 100644
--- a/front/src/views/auth/PasswordResetConfirm.vue
+++ b/front/src/views/auth/PasswordResetConfirm.vue
@@ -5,7 +5,7 @@
         <h2>{{ $t('Change your password') }}</h2>
         <form v-if="!success" class="ui form" @submit.prevent="submit()">
           <div v-if="errors.length > 0" class="ui negative message">
-            <div class="header">{{ $('Error while changing your password') }}</div>
+            <div class="header">{{ $t('Error while changing your password') }}</div>
             <ul class="list">
               <li v-for="error in errors">{{ error }}</li>
             </ul>
-- 
GitLab