202 lines
No EOL
9 KiB
Vue
202 lines
No EOL
9 KiB
Vue
<template>
|
|
<div class="main d-flex w-100">
|
|
<div class="container d-flex flex-column">
|
|
<div class="row vh-100">
|
|
<div class="col-sm-10 col-md-8 col-lg-6 mx-auto d-table h-100">
|
|
<div class="d-table-cell align-middle">
|
|
<div class="text-center mt-4">
|
|
<h1 class="h2">
|
|
Toolshed
|
|
</h1>
|
|
|
|
<p class="lead" v-if="msg">
|
|
{{ msg }}
|
|
</p>
|
|
<p class="lead" v-else>
|
|
Create an account to get started
|
|
</p>
|
|
</div>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="m-sm-4">
|
|
<form role="form" method="post" @submit.prevent="do_register">
|
|
<div :class="errors.username||errors.domain?['mb-3','is-invalid']:['mb-3']">
|
|
<label class="form-label">Username</label>
|
|
<div class="input-group">
|
|
<input class="form-control form-control-lg"
|
|
type="text" v-model="form.username" id="validationCustomUsername"
|
|
placeholder="Enter your username" required/>
|
|
|
|
<span class="input-group-text form-control-lg">@</span>
|
|
<select class="form-control form-control-lg"
|
|
id="exampleFormControlSelect1"
|
|
placeholder="Domain" v-model="form.domain" required>
|
|
<option v-for="domain in domains">{{ domain }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="invalid-feedback">
|
|
{{ errors.username }}{{ errors.domain }}
|
|
</div>
|
|
</div>
|
|
|
|
<div :class="errors.email?['mb-3','is-invalid']:['mb-3']">
|
|
<label class="form-label">Email</label>
|
|
<input class="form-control form-control-lg" type="email"
|
|
:class="errors.email?['is-invalid']:[]"
|
|
v-model="form.email" placeholder="Enter your email"/>
|
|
<div class="invalid-feedback">{{ errors.email }}</div>
|
|
</div>
|
|
|
|
<input type="text" class="visually-hidden" autocomplete="username"
|
|
tabindex="-1" aria-hidden="true"
|
|
v-model="fullHandle"/>
|
|
|
|
<div :class="errors.password?['mb-3','is-invalid']:['mb-3']">
|
|
<label class="form-label">Password</label>
|
|
<input class="form-control form-control-lg" type="password"
|
|
:class="errors.password?['is-invalid']:[]"
|
|
v-model="form.password" placeholder="Enter your password"/>
|
|
<div class="invalid-feedback">{{ errors.password }}</div>
|
|
</div>
|
|
|
|
<div :class="errors.password2?['mb-3','is-invalid']:['mb-3']">
|
|
<label class="form-label">Password Check</label>
|
|
<input class="form-control form-control-lg" type="password"
|
|
:class="errors.password2?['is-invalid']:[]"
|
|
v-model="password2" placeholder="Enter your password again"/>
|
|
<div class="invalid-feedback">{{ errors.password2 }}</div>
|
|
</div>
|
|
|
|
<div class="text-center mt-3">
|
|
<button type="submit" class="btn btn-lg btn-primary">
|
|
Register
|
|
</button>
|
|
</div>
|
|
</form>
|
|
<br/>
|
|
<div class="text-center">
|
|
<p class="mb-0 text-muted">
|
|
Already have an account?
|
|
<router-link :to="{name: 'login'}">Login</router-link>
|
|
</p>
|
|
<p class="mb-0 text-muted">
|
|
Connect with existing account?
|
|
<router-link :to="{name: 'pairing'}">Pairing</router-link>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {mapActions} from 'vuex';
|
|
import {ServerSet, createNullAuth} from '../federation';
|
|
import NeighborsCache from '../neigbors';
|
|
|
|
export default {
|
|
name: 'Register',
|
|
data() {
|
|
return {
|
|
msg: 'Register new account',
|
|
password2: '',
|
|
form: {
|
|
username: '',
|
|
domain: '',
|
|
email: '',
|
|
password: '',
|
|
},
|
|
errors: {
|
|
username: null,
|
|
domain: null,
|
|
email: null,
|
|
password: null,
|
|
password2: null,
|
|
},
|
|
domains: []
|
|
}
|
|
},
|
|
computed: {
|
|
fullHandle: {
|
|
get() {
|
|
return this.form.domain ? `${this.form.username}@${this.form.domain}` : this.form.username;
|
|
},
|
|
set(value) {
|
|
this.applyHandle(value);
|
|
}
|
|
}
|
|
},
|
|
watch: {
|
|
// Catches the same "user@domain" shape when it's typed or pasted
|
|
// directly into the visible username field instead.
|
|
'form.username'(value) {
|
|
if (value.includes('@')) {
|
|
this.applyHandle(value);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
...mapActions(['lookupServer']),
|
|
applyHandle(value) {
|
|
const atIndex = value.indexOf('@');
|
|
if (atIndex === -1) {
|
|
this.form.username = value;
|
|
return;
|
|
}
|
|
this.form.username = value.slice(0, atIndex);
|
|
const domain = value.slice(atIndex + 1);
|
|
if (this.domains.includes(domain)) {
|
|
this.form.domain = domain;
|
|
}
|
|
},
|
|
do_register() {
|
|
console.log('do_register');
|
|
console.log(this.form);
|
|
if (this.form.password !== this.password2) {
|
|
this.errors.password2 = 'Passwords do not match';
|
|
return;
|
|
} else {
|
|
this.errors.password2 = null;
|
|
}
|
|
const user = this.form.username + '@' + this.form.domain;
|
|
var unreachable = new NeighborsCache();
|
|
var nullAuth = createNullAuth({})
|
|
this.lookupServer({username: user}).then(servers => new ServerSet(servers, unreachable))
|
|
.then(set => set.post(nullAuth, '/auth/register/', this.form))
|
|
.then(response => {
|
|
if (response.errors) {
|
|
console.error('Error:', response.errors);
|
|
this.errors = response.errors;
|
|
return;
|
|
}
|
|
console.log('Success:', response);
|
|
this.msg = 'Success';
|
|
localStorage.setItem('user', user);
|
|
this.$router.push('/login');
|
|
})
|
|
}
|
|
},
|
|
mounted() {
|
|
try {
|
|
fetch('/local/domains')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
this.domains = data;
|
|
});
|
|
} catch (e) {
|
|
console.error('Error:', e);
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.visually-hidden {
|
|
display: none;
|
|
}
|
|
</style> |