Change models, new migrations, fix front and make tests work
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
92d2045735
commit
20cd1bb579
@ -27,5 +27,11 @@ config :logger, :console,
|
||||
import_config "#{Mix.env}.exs"
|
||||
|
||||
config :eventos, EventosWeb.Guardian,
|
||||
issuer: "Eventos",
|
||||
secret_key: "ty0WM7YBE3ojvxoUQxo8AERrNpfbXnIJ82ovkPdqbUFw31T5LcK8wGjaOiReVQjo"
|
||||
issuer: "eventos",
|
||||
secret_key: "ty0WM7YBE3ojvxoUQxo8AERrNpfbXnIJ82ovkPdqbUFw31T5LcK8wGjaOiReVQjo"
|
||||
|
||||
config :guardian, Guardian.DB,
|
||||
repo: Eventos.Repo,
|
||||
schema_name: "guardian_tokens", # default
|
||||
token_types: ["refresh_token"], # store all token types if not set
|
||||
sweep_interval: 60 # default: 60 minutes
|
@ -50,6 +50,7 @@ config :phoenix, :stacktrace_depth, 20
|
||||
# Configure your database
|
||||
config :eventos, Eventos.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
types: Eventos.PostgresTypes,
|
||||
username: "elixir",
|
||||
password: "elixir",
|
||||
database: "eventos_dev",
|
||||
|
@ -7,7 +7,10 @@ config :eventos, EventosWeb.Endpoint,
|
||||
server: false
|
||||
|
||||
# Print only warnings and errors during test
|
||||
config :logger, level: :warn
|
||||
config :logger,
|
||||
backends: [:console],
|
||||
compile_time_purge_level: :debug,
|
||||
level: :info
|
||||
|
||||
# Configure your database
|
||||
config :eventos, Eventos.Repo,
|
||||
@ -16,4 +19,5 @@ config :eventos, Eventos.Repo,
|
||||
password: "elixir",
|
||||
database: "eventos_test",
|
||||
hostname: "localhost",
|
||||
pool: Ecto.Adapters.SQL.Sandbox
|
||||
pool: Ecto.Adapters.SQL.Sandbox,
|
||||
types: Eventos.PostgresTypes
|
||||
|
@ -4,7 +4,7 @@ var path = require('path')
|
||||
module.exports = {
|
||||
build: {
|
||||
env: require('./prod.env'),
|
||||
index: path.resolve(__dirname, '../../lib/eventos_web/templates/app/index.html.eex'),
|
||||
index: path.resolve(__dirname, '../../lib/eventos_web/templates/page/index.html.eex'),
|
||||
assetsRoot: path.resolve(__dirname, '../../priv/static'),
|
||||
assetsSubDirectory: '',
|
||||
assetsPublicPath: '/',
|
||||
|
@ -4,11 +4,11 @@
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
|
||||
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBF37pw38j0giICt73TCAPNogc07Upe_Q4&libraries=places"></script>
|
||||
<meta charset="utf-8">
|
||||
<title>libre-event</title>
|
||||
<title>Eventos</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
Mets du JS.
|
||||
You need to activate your JS doug.
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
6
js/package-lock.json
generated
6
js/package-lock.json
generated
@ -13648,9 +13648,9 @@
|
||||
}
|
||||
},
|
||||
"vuetify": {
|
||||
"version": "0.17.6",
|
||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-0.17.6.tgz",
|
||||
"integrity": "sha512-geIGnXjYEhUn1dr+g8FCFqvV6xUbALXNJ3UZQ32T0SJdGJh/JLsScINTxV+Pxt1F36s+YRnuFyHLiFOSnuVzjA=="
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-1.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-eM61PPNwM0lXYaUzY0MXA7sp/N4wqxlEMcALsOBneLObVS+OgpX4Zszb7HqAOSVXipNRSP8X5ZV5TgbZscly1Q=="
|
||||
},
|
||||
"vuetify-google-autocomplete": {
|
||||
"version": "1.1.0",
|
||||
|
@ -21,7 +21,7 @@
|
||||
"vue-markdown": "^2.2.4",
|
||||
"vue-router": "^3.0.1",
|
||||
"vue2-google-maps": "^0.8.4",
|
||||
"vuetify": "^0.17.6",
|
||||
"vuetify": "^1.0.0-beta.2",
|
||||
"vuetify-google-autocomplete": "^1.1.0",
|
||||
"vuex": "^2.5.0",
|
||||
"vuex-i18n": "1.8.0"
|
||||
|
@ -76,7 +76,6 @@
|
||||
|
||||
<script>
|
||||
|
||||
import auth from '@/auth/index';
|
||||
import NavBar from '@/components/NavBar';
|
||||
|
||||
export default {
|
||||
@ -105,15 +104,7 @@ export default {
|
||||
show_new_event_button: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.checkAuthMethod();
|
||||
},
|
||||
methods: {
|
||||
checkAuthMethod() {
|
||||
if (auth.checkAuth(this.$store)) {
|
||||
this.show_new_event_button = true;
|
||||
}
|
||||
},
|
||||
showMenuItem(elem) {
|
||||
return elem !== null && this.$store.state.user && this.$store.state.user.roles !== undefined ? this.$store.state.user.roles.includes(elem) : true;
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { API_HOST, API_PATH } from './_entrypoint';
|
||||
|
||||
const jsonLdMimeType = 'application/ld+json';
|
||||
const jsonLdMimeType = 'application/json';
|
||||
|
||||
export default function eventFetch(url, store, optionsarg = {}) {
|
||||
const options = optionsarg;
|
||||
|
@ -1,87 +1,61 @@
|
||||
import router from '../router/index';
|
||||
import { API_HOST, API_PATH } from '../api/_entrypoint';
|
||||
|
||||
// URL and endpoint constants
|
||||
const LOGIN_URL = `${API_HOST}${API_PATH}/login`;
|
||||
const SIGNUP_URL = `${API_HOST}${API_PATH}/users/`;
|
||||
const CHECK_AUTH = `${API_HOST}${API_PATH}/users/`;
|
||||
const CHECK_AUTH = `${API_HOST}${API_PATH}/user/`;
|
||||
const REFRESH_TOKEN = `${API_HOST}${API_PATH}/token/refresh`;
|
||||
|
||||
function AuthError(field, message) {
|
||||
this.field = field;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
AuthError.prototype.toString = function AuthErrorToString() {
|
||||
return `AuthError: ${this.message}`;
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
// User object will let us check authentication status
|
||||
user: false,
|
||||
authenticated: false,
|
||||
token: false,
|
||||
|
||||
// Send a request to the login URL and save the returned JWT
|
||||
login(creds, $store, redirect, error) {
|
||||
login(creds, success, error) {
|
||||
fetch(LOGIN_URL, { method: 'POST', body: creds, headers: { 'Content-Type': 'application/json' } })
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
if (data.code >= 300) {
|
||||
throw new AuthError(null, data.message);
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
}
|
||||
$store.commit('LOGIN_USER');
|
||||
|
||||
throw response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
localStorage.setItem('token', data.token);
|
||||
localStorage.setItem('refresh_token', data.refresh_token);
|
||||
this.getUser(
|
||||
$store,
|
||||
() => router.push(redirect)
|
||||
);
|
||||
|
||||
}).catch((err) => {
|
||||
error(err);
|
||||
});
|
||||
// localStorage.setItem('refresh_token', data.refresh_token);
|
||||
return success(data);
|
||||
})
|
||||
.catch(err => error(err));
|
||||
},
|
||||
|
||||
signup(creds, $store, redirect, error) {
|
||||
signup(creds, success, error) {
|
||||
fetch(SIGNUP_URL, { method: 'POST', body: creds, headers: { 'Content-Type': 'application/json' } })
|
||||
.then(response => response.json())
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
}
|
||||
throw response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.error) {
|
||||
throw new AuthError(data.error.field, data.error.message);
|
||||
}
|
||||
|
||||
$store.commit('LOGIN_USER');
|
||||
localStorage.setItem('token', data.token);
|
||||
localStorage.setItem('refresh_token', data.refresh_token);
|
||||
// localStorage.setItem('refresh_token', data.refresh_token);
|
||||
|
||||
if (redirect) {
|
||||
router.push(redirect);
|
||||
}
|
||||
}).catch((err) => {
|
||||
error(err);
|
||||
});
|
||||
return success(data);
|
||||
}).catch(err => error(err));
|
||||
},
|
||||
refreshToken(store, successHandler, errorHandler) {
|
||||
const refreshToken = localStorage.getItem('refresh_token');
|
||||
console.log("We are refreshing the jwt token");
|
||||
fetch(REFRESH_TOKEN, { method: 'POST', body: JSON.stringify({refresh_token: refreshToken}), headers: { 'Content-Type': 'application/json' }})
|
||||
console.log('We are refreshing the jwt token');
|
||||
fetch(REFRESH_TOKEN, { method: 'POST', body: JSON.stringify({ refresh_token: refreshToken }), headers: { 'Content-Type': 'application/json' } })
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
} else {
|
||||
errorHandler('Error while authenticating');
|
||||
}
|
||||
return errorHandler('Error while authenticating');
|
||||
})
|
||||
.then((response) => {
|
||||
console.log("We have a new token");
|
||||
console.log('We have a new token');
|
||||
this.authenticated = true;
|
||||
store.commit('LOGIN_USER', response);
|
||||
localStorage.setItem('token', response.token);
|
||||
console.log("Let's try to auth again");
|
||||
this.getUser(store, successHandler, errorHandler);
|
||||
successHandler();
|
||||
});
|
||||
},
|
||||
@ -114,19 +88,8 @@ export default {
|
||||
return expirationDate < new Date();
|
||||
},
|
||||
|
||||
checkAuth(store = null) {
|
||||
const token = localStorage.getItem('token');
|
||||
if (store && token) {
|
||||
this.getUser(store,() => null, () => null);
|
||||
}
|
||||
/* if (!!token && store && !this.isTokenExpired(token)) {
|
||||
this.refreshToken(store, () => null, () => null);
|
||||
} */
|
||||
return !!token;
|
||||
},
|
||||
|
||||
getUser(store, successHandler, errorHandler) {
|
||||
console.log("We are checking the auth");
|
||||
console.log('We are checking the auth');
|
||||
this.token = localStorage.getItem('token');
|
||||
const options = {};
|
||||
options.headers = new Headers();
|
||||
@ -135,16 +98,14 @@ export default {
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
} else {
|
||||
errorHandler('Error while authenticating');
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
return errorHandler('Error while authenticating');
|
||||
}).then((response) => {
|
||||
this.authenticated = true;
|
||||
console.log(response);
|
||||
store.commit('SAVE_USER', response);
|
||||
successHandler();
|
||||
});
|
||||
store.commit('LOAD_USER', response.data);
|
||||
return successHandler();
|
||||
});
|
||||
},
|
||||
|
||||
// The object to be passed as a header for authenticated requests
|
||||
|
@ -29,11 +29,16 @@
|
||||
:src="account.avatarRemoteUrl"
|
||||
>
|
||||
</v-avatar>
|
||||
<v-card-title class="pl-5 pt-5">
|
||||
<div class="display-1 pl-5 pt-5">@{{ account.username }}<span v-if="account.server">@{{ account.server.address }}</span></div>
|
||||
</v-card-title>
|
||||
<v-card-text v-if="account.description" v-html="account.description"></v-card-text>
|
||||
</div>
|
||||
<v-container fluid grid-list-lg>
|
||||
<v-layout row>
|
||||
<v-flex xs7>
|
||||
<div class="headline">{{ account.display_name }}</div>
|
||||
<div><span class="subheading">@{{ account.username }}</span><span v-if="account.server">@{{ account.server.address }}</span></div>
|
||||
<v-card-text v-if="account.description" v-html="account.description"></v-card-text>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-layout>
|
||||
<v-list three-line>
|
||||
<v-list-tile>
|
||||
@ -69,7 +74,7 @@
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
<v-container fluid grid-list-md v-if="account.participatingEvents.length > 0">
|
||||
<v-container fluid grid-list-md v-if="account.participatingEvents && account.participatingEvents.length > 0">
|
||||
<v-subheader>Participated at</v-subheader>
|
||||
<v-layout row wrap>
|
||||
<v-flex v-for="event in account.participatingEvents" :key="event.id">
|
||||
@ -110,7 +115,7 @@
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-container fluid grid-list-md v-if="account.organizingEvents.length > 0">
|
||||
<v-container fluid grid-list-md v-if="account.organizingEvents && account.organizingEvents.length > 0">
|
||||
<v-subheader>Organized events</v-subheader>
|
||||
<v-layout row wrap>
|
||||
<v-flex v-for="event in account.organizingEvents" :key="event.id">
|
||||
@ -178,11 +183,12 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
fetchData() {
|
||||
eventFetch('/accounts/' + this.id, this.$store)
|
||||
eventFetch(`/accounts/${this.id}`, this.$store)
|
||||
.then(response => response.json())
|
||||
.then((response) => {
|
||||
this.account = response;
|
||||
this.account = response.data;
|
||||
this.loading = false;
|
||||
console.log(this.account);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,10 @@
|
||||
<v-form>
|
||||
<v-text-field
|
||||
label="Name of the category"
|
||||
v-model="category.name"
|
||||
v-model="category.title"
|
||||
:counter="100"
|
||||
required
|
||||
></v-text-field>
|
||||
<input type="file" @change="processFile($event.target)">
|
||||
</v-form>
|
||||
<v-btn color="primary" @click="create">Create category</v-btn>
|
||||
</div>
|
||||
@ -22,32 +21,20 @@
|
||||
data() {
|
||||
return {
|
||||
category: {
|
||||
name: '',
|
||||
imageDataUri: null,
|
||||
title: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
create() {
|
||||
const router = this.$router;
|
||||
eventFetch('/categories', this.$store, { method: 'POST', body: JSON.stringify(this.category) })
|
||||
eventFetch('/categories', this.$store, { method: 'POST', body: JSON.stringify({ category: this.category }) })
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
router.push('/category')
|
||||
});
|
||||
},
|
||||
processFile(target) {
|
||||
const reader = new FileReader();
|
||||
const file = target.files[0];
|
||||
reader.addEventListener('load', () => {
|
||||
this.category.imageDataUri = reader.result;
|
||||
});
|
||||
|
||||
if (file) {
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -11,7 +11,7 @@
|
||||
</v-card-media>
|
||||
<v-card-title primary-title>
|
||||
<div>
|
||||
<h3 class="headline mb-0">{{ category.name }}</h3>
|
||||
<h3 class="headline mb-0">{{ category.title }}</h3>
|
||||
<div>{{ category.description }}</div>
|
||||
</div>
|
||||
</v-card-title>
|
||||
@ -49,9 +49,9 @@
|
||||
fetchData() {
|
||||
eventFetch('/categories', this.$store)
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
.then((response) => {
|
||||
this.loading = false;
|
||||
this.categories = data['hydra:member'];
|
||||
this.categories = response.data;
|
||||
});
|
||||
},
|
||||
deleteCategory(categoryId) {
|
||||
|
@ -36,7 +36,7 @@
|
||||
<v-select
|
||||
v-bind:items="categories"
|
||||
v-model="event.category"
|
||||
item-text="name"
|
||||
item-text="title"
|
||||
item-value="@id"
|
||||
label="Categories"
|
||||
single-line
|
||||
@ -62,7 +62,7 @@
|
||||
<v-stepper-step step="2" :complete="e1 > 2">Date and place</v-stepper-step>
|
||||
<v-stepper-content step="2">
|
||||
Event starts at:
|
||||
<v-text-field type="datetime-local" v-model="event.startDate"></v-text-field>
|
||||
<v-text-field type="datetime-local" v-model="event.begins_on"></v-text-field>
|
||||
<!--<v-layout row wrap>
|
||||
<v-flex md6>
|
||||
<v-dialog
|
||||
@ -113,7 +113,7 @@
|
||||
</v-flex>
|
||||
</v-layout>-->
|
||||
Event ends at:
|
||||
<v-text-field type="datetime-local" v-model="event.endDate"></v-text-field>
|
||||
<v-text-field type="datetime-local" v-model="event.ends_on"></v-text-field>
|
||||
<!--<v-layout row wrap>
|
||||
<v-flex md6>
|
||||
<v-dialog
|
||||
@ -216,8 +216,8 @@
|
||||
event: {
|
||||
title: '',
|
||||
description: '',
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
begins_on: new Date(),
|
||||
ends_on: new Date(),
|
||||
seats: 0,
|
||||
address: {
|
||||
description: null,
|
||||
@ -261,12 +261,12 @@
|
||||
// '@type': 'Tag',
|
||||
});
|
||||
});
|
||||
this.event.organizer = "/accounts/" + this.$store.state.user.account.id;
|
||||
this.event.participants = ["/accounts/" + this.$store.state.user.account.id];
|
||||
this.event.organizer_id = this.$store.state.user.account.id;
|
||||
this.event.participants = [this.$store.state.user.account.id];
|
||||
this.event.price = parseFloat(this.event.price);
|
||||
|
||||
if (this.id === undefined) {
|
||||
eventFetch('/events', this.$store, {method: 'POST', body: JSON.stringify(this.event)})
|
||||
eventFetch('/events', this.$store, {method: 'POST', body: JSON.stringify({ event: this.event })})
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
this.loading = false;
|
||||
@ -284,17 +284,17 @@
|
||||
fetchCategories() {
|
||||
eventFetch('/categories', this.$store)
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
.then((response) => {
|
||||
this.loading = false;
|
||||
this.categories = data['hydra:member'];
|
||||
this.categories = response.data;
|
||||
});
|
||||
},
|
||||
fetchTags() {
|
||||
eventFetch('/tags', this.$store)
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
.then((response) => {
|
||||
this.loading = false;
|
||||
data['hydra:member'].forEach((tag) => {
|
||||
response.data.forEach((tag) => {
|
||||
this.tagsFetched.push(tag.name);
|
||||
});
|
||||
});
|
||||
|
@ -26,7 +26,7 @@
|
||||
<div class="headline">{{ event.title }}</div>
|
||||
</v-card-title>
|
||||
<v-container>
|
||||
<span class="grey--text">{{ event.startDate | formatDate }} à <router-link :to="{name: 'EventList', params: {location: geocode(event.address.geo.latitude, event.address.geo.longitude, 10) }}">{{ event.address.addressLocality }}</router-link></span><br>
|
||||
<!--<span class="grey--text">{{ event.startDate | formatDate }} à <router-link :to="{name: 'EventList', params: {location: geocode(event.address.geo.latitude, event.address.geo.longitude, 10) }}">{{ event.address.addressLocality }}</router-link></span><br>-->
|
||||
<p><vue-markdown>{{ event.description }}</vue-markdown></p>
|
||||
<p v-if="event.organizer">Organisé par <router-link :to="{name: 'Account', params: {'id': event.organizer.id}}">{{ event.organizer.username }}</router-link></p>
|
||||
</v-container>
|
||||
@ -93,9 +93,9 @@
|
||||
this.locationChip = true;
|
||||
eventFetch(queryString, this.$store)
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
.then((response) => {
|
||||
this.loading = false;
|
||||
this.events = data['hydra:member'];
|
||||
this.events = response.data;
|
||||
});
|
||||
},
|
||||
deleteEvent(id) {
|
||||
|
@ -98,7 +98,7 @@
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
this.loading = false;
|
||||
this.categories = data['hydra:member'];
|
||||
this.categories = data;
|
||||
});
|
||||
},
|
||||
getAddressData: function (addressData) {
|
||||
|
@ -58,7 +58,7 @@
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
this.loading = false;
|
||||
this.groups = data['hydra:member'];
|
||||
this.groups = data;
|
||||
});
|
||||
},
|
||||
deleteEvent(id) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<h1 class="welcome" v-if="$store.state.user">{{ $t("home.welcome", { 'username': $store.state.user.username}) }}</h1>
|
||||
<h1 class="welcome" v-if="$store.state.user">{{ $t("home.welcome", { 'username': this.displayed_name }) }}</h1>
|
||||
<h1 class="welcome" v-else>{{ $t("home.welcome_off", { 'username': $store.state.user.username}) }}</h1>
|
||||
<router-link :to="{ name: 'EventList' }">{{ $t('home.events') }}</router-link>
|
||||
<router-link v-if="$store.state.user === false" :to="{ name: 'Login' }">{{ $t('home.login') }}</router-link>
|
||||
@ -48,12 +48,17 @@ export default {
|
||||
mounted() {
|
||||
// this.fetchLocations();
|
||||
},
|
||||
computed: {
|
||||
displayed_name: function() {
|
||||
return this.$store.state.user.account.display_name === null ? this.$store.state.user.account.username : this.$store.state.user.account.display_name
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
fetchLocations() {
|
||||
eventFetch('/locations', this.$store)
|
||||
.then((response) => (response.json()))
|
||||
.then((response) => {
|
||||
this.locations = response['hydra:member'];
|
||||
this.locations = response;
|
||||
});
|
||||
},
|
||||
geoLocalize() {
|
||||
|
@ -65,10 +65,19 @@
|
||||
methods: {
|
||||
loginAction(e) {
|
||||
e.preventDefault();
|
||||
auth.login(JSON.stringify(this.credentials), this.$store, '/', (error) => {
|
||||
this.error.show = true;
|
||||
this.error.text = error.message;
|
||||
this.error.field[error.field] = true;
|
||||
auth.login(JSON.stringify(this.credentials), (data) => {
|
||||
this.$store.commit('LOGIN_USER', data.user);
|
||||
this.$router.push({ name: 'Home' });
|
||||
}, (error) => {
|
||||
Promise.resolve(error).then((errorMsg) => {
|
||||
console.log(errorMsg);
|
||||
this.error.show = true;
|
||||
this.error.text = this.$t(errorMsg.display_error);
|
||||
}).catch((e) => {
|
||||
console.log(e);
|
||||
this.error.show = true;
|
||||
this.error.text = e.message;
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
|
@ -58,7 +58,7 @@
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-menu>
|
||||
<v-btn flat @click="$router.push({name: 'Account', params: {'id': getUser().account.id}})" v-if="$store.state.isLogged && getUser()">{{ getUser().username }}</v-btn>
|
||||
<v-btn flat @click="$router.push({name: 'Account', params: {'id': getUser().account.id}})" v-if="$store.state.user">{{ this.displayed_name }}</v-btn>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
@ -95,6 +95,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayed_name: function() {
|
||||
return this.$store.state.user.account.display_name === null ? this.$store.state.user.account.username : this.$store.state.user.account.display_name
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getUser() {
|
||||
return this.$store.state.user === undefined ? false : this.$store.state.user;
|
||||
|
@ -72,7 +72,11 @@
|
||||
methods: {
|
||||
registerAction(e) {
|
||||
e.preventDefault();
|
||||
auth.signup(JSON.stringify(this.credentials), this.$store, {name: 'Home'}, (error) => {
|
||||
auth.signup(JSON.stringify(this.credentials), (response) => {
|
||||
console.log(response);
|
||||
this.$store.commit('LOGIN_USER', response.user);
|
||||
this.$router.push({ name: 'Home' });
|
||||
}, (error) => {
|
||||
this.error.show = true;
|
||||
this.error.text = error.message;
|
||||
this.error.field[error.field] = true;
|
||||
|
@ -12,4 +12,9 @@ export default {
|
||||
title: "Votre liste d'événements",
|
||||
},
|
||||
},
|
||||
session: {
|
||||
error: {
|
||||
bad_login: 'Erreur lors de la connexion : Votre nom d\'utilisateur ou votre mot de passe est incorrect',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -10,8 +10,9 @@ import VuexI18n from 'vuex-i18n';
|
||||
import 'vuetify/dist/vuetify.min.css';
|
||||
import App from '@/App';
|
||||
import router from '@/router';
|
||||
import storeData from './store/index';
|
||||
import translations from './i18n/index';
|
||||
import storeData from '@/store/index';
|
||||
import translations from '@/i18n/index';
|
||||
import auth from '@/auth';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
@ -46,6 +47,19 @@ Object.entries(translations).forEach((key) => {
|
||||
Vue.i18n.set(language);
|
||||
Vue.i18n.fallback('en');
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.matched.some(record => record.meta.requiredAuth) && store.state.user === undefined || store.state.user == null) {
|
||||
next({
|
||||
name: 'Login',
|
||||
query: { redirect: to.fullPath }
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
auth.getUser(store, () => {}, () => {});
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
|
@ -14,7 +14,6 @@ import Account from '@/components/Account/Account';
|
||||
import CreateGroup from '@/components/Group/Create';
|
||||
import Group from '@/components/Group/Group';
|
||||
import GroupList from '@/components/Group/GroupList';
|
||||
import Auth from '@/auth/index';
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
@ -118,16 +117,4 @@ const router = new Router({
|
||||
],
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.matched.some(record => record.meta.requiredAuth) && !Auth.checkAuth()) {
|
||||
console.log('needs login');
|
||||
next({
|
||||
path: '/',
|
||||
query: { redirect: to.fullPath }
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
@ -1,21 +1,26 @@
|
||||
import { LOGIN_USER, LOGOUT_USER, SAVE_USER } from './mutation-types';
|
||||
import { LOGIN_USER, LOGOUT_USER, LOAD_USER } from './mutation-types';
|
||||
|
||||
const state = {
|
||||
isLogged: !!localStorage.getItem('token'),
|
||||
user: false,
|
||||
};
|
||||
|
||||
/* eslint-disable */
|
||||
const mutations = {
|
||||
[LOGIN_USER](state) {
|
||||
[LOGIN_USER](state, user) {
|
||||
state.isLogged = true;
|
||||
state.user = user;
|
||||
},
|
||||
|
||||
[LOAD_USER](state, user) {
|
||||
state.user = user;
|
||||
},
|
||||
|
||||
[LOGOUT_USER](state) {
|
||||
state.isLogged = false;
|
||||
},
|
||||
[SAVE_USER](state, user) {
|
||||
state.user = user;
|
||||
state.user = null;
|
||||
},
|
||||
};
|
||||
/* eslint-enable */
|
||||
|
||||
export default { state, mutations };
|
||||
|
@ -1,3 +1,3 @@
|
||||
export const LOGIN_USER = 'LOGIN_USER';
|
||||
export const LOAD_USER = 'LOAD_USER';
|
||||
export const LOGOUT_USER = 'LOGOUT_USER';
|
||||
export const SAVE_USER = 'SAVE_USER';
|
||||
|
@ -1,22 +1,23 @@
|
||||
defmodule Eventos.Accounts.Account do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Eventos.Accounts.{Account, GroupAccount, GroupRequest, Group, User}
|
||||
alias Eventos.Accounts.{Account, User}
|
||||
alias Eventos.Groups.{Group, Member, Request}
|
||||
alias Eventos.Events.Event
|
||||
|
||||
schema "accounts" do
|
||||
field :username, :string
|
||||
field :description, :string
|
||||
field :display_name, :string
|
||||
field :domain, :string, default: nil
|
||||
field :domain, :string
|
||||
field :private_key, :string
|
||||
field :public_key, :string
|
||||
field :suspended, :boolean, default: false
|
||||
field :uri, :string
|
||||
field :url, :string
|
||||
has_many :organized_events, Event
|
||||
many_to_many :groups, Group, join_through: GroupAccount
|
||||
has_many :group_request, GroupRequest
|
||||
field :username, :string
|
||||
has_many :organized_events, Event, [foreign_key: :organizer_id]
|
||||
many_to_many :groups, Group, join_through: Member
|
||||
has_many :group_request, Request
|
||||
has_one :user, User
|
||||
|
||||
timestamps()
|
||||
@ -26,7 +27,14 @@ defmodule Eventos.Accounts.Account do
|
||||
def changeset(%Account{} = account, attrs) do
|
||||
account
|
||||
|> cast(attrs, [:username, :domain, :display_name, :description, :private_key, :public_key, :suspended, :uri, :url])
|
||||
|> validate_required([:username, :display_name, :description, :private_key, :public_key, :suspended])
|
||||
|> validate_required([:username, :public_key, :suspended, :uri, :url])
|
||||
|> unique_constraint(:username, name: :accounts_username_domain_index)
|
||||
end
|
||||
|
||||
def registration_changeset(%Account{} = account, attrs) do
|
||||
account
|
||||
|> cast(attrs, [:username, :domain, :display_name, :description, :private_key, :public_key, :suspended, :uri, :url])
|
||||
|> validate_required([:username, :public_key, :suspended, :uri, :url])
|
||||
|> unique_constraint(:username)
|
||||
end
|
||||
end
|
||||
|
@ -4,130 +4,8 @@ defmodule Eventos.Accounts do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
import Logger
|
||||
alias Eventos.Repo
|
||||
|
||||
alias Eventos.Accounts.User
|
||||
|
||||
@doc """
|
||||
Returns the list of users.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_users()
|
||||
[%User{}, ...]
|
||||
|
||||
"""
|
||||
def list_users do
|
||||
Repo.all(User)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single user.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the User does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_user!(123)
|
||||
%User{}
|
||||
|
||||
iex> get_user!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_user!(id), do: Repo.get!(User, id)
|
||||
|
||||
|
||||
@doc """
|
||||
Get an user by email
|
||||
"""
|
||||
def find(email) do
|
||||
Repo.get_by!(User, email: email)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Authenticate user
|
||||
"""
|
||||
def authenticate(%{user: user, password: password}) do
|
||||
# Does password match the one stored in the database?
|
||||
Logger.debug(user.password_hash)
|
||||
Logger.debug(password)
|
||||
case Comeonin.Argon2.checkpw(password, user.password_hash) do
|
||||
true ->
|
||||
# Yes, create and return the token
|
||||
EventosWeb.Guardian.encode_and_sign(user)
|
||||
_ ->
|
||||
# No, return an error
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@doc """
|
||||
Creates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_user(%{field: value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> create_user(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_user(attrs \\ %{}) do
|
||||
%User{}
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_user(user, %{field: new_value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> update_user(user, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_user(%User{} = user, attrs) do
|
||||
user
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a User.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_user(user)
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> delete_user(user)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_user(%User{} = user) do
|
||||
Repo.delete(user)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking user changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_user(user)
|
||||
%Ecto.Changeset{source: %User{}}
|
||||
|
||||
"""
|
||||
def change_user(%User{} = user) do
|
||||
User.changeset(user, %{})
|
||||
end
|
||||
import Logger
|
||||
|
||||
alias Eventos.Accounts.Account
|
||||
|
||||
@ -158,7 +36,14 @@ defmodule Eventos.Accounts do
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_account!(id), do: Repo.get!(Account, id)
|
||||
def get_account!(id) do
|
||||
account = Repo.get!(Account, id)
|
||||
end
|
||||
|
||||
def get_account_with_everything!(id) do
|
||||
account = Repo.get!(Account, id)
|
||||
|> Repo.preload :organized_events
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a account.
|
||||
@ -225,291 +110,177 @@ defmodule Eventos.Accounts do
|
||||
Account.changeset(account, %{})
|
||||
end
|
||||
|
||||
alias Eventos.Accounts.Group
|
||||
alias Eventos.Accounts.User
|
||||
|
||||
@doc """
|
||||
Returns the list of groups.
|
||||
Returns the list of users.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_groups()
|
||||
[%Group{}, ...]
|
||||
iex> list_users()
|
||||
[%User{}, ...]
|
||||
|
||||
"""
|
||||
def list_groups do
|
||||
Repo.all(Group)
|
||||
def list_users do
|
||||
Repo.all(User)
|
||||
end
|
||||
|
||||
def list_users_with_accounts do
|
||||
Repo.all(User)
|
||||
|> Repo.preload :account
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single group.
|
||||
Gets a single user.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Group does not exist.
|
||||
Raises `Ecto.NoResultsError` if the User does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_group!(123)
|
||||
%Group{}
|
||||
iex> get_user!(123)
|
||||
%User{}
|
||||
|
||||
iex> get_group!(456)
|
||||
iex> get_user!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_group!(id), do: Repo.get!(Group, id)
|
||||
def get_user!(id), do: Repo.get!(User, id)
|
||||
|
||||
def get_user_with_account!(id) do
|
||||
Repo.get!(User, id)
|
||||
|> Repo.preload :account
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a group.
|
||||
Get an user by email
|
||||
"""
|
||||
def find_by_email(email) do
|
||||
user = Repo.get_by(User, email: email)
|
||||
|> Repo.preload :account
|
||||
end
|
||||
|
||||
@doc """
|
||||
Authenticate user
|
||||
"""
|
||||
def authenticate(%{user: user, password: password}) do
|
||||
# Does password match the one stored in the database?
|
||||
case Comeonin.Argon2.checkpw(password, user.password_hash) do
|
||||
true ->
|
||||
# Yes, create and return the token
|
||||
EventosWeb.Guardian.encode_and_sign(user)
|
||||
_ ->
|
||||
# No, return an error
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Register user
|
||||
"""
|
||||
def register(%{email: email, password: password, username: username}) do
|
||||
{:ok, {privkey, pubkey}} = RsaEx.generate_keypair("4096")
|
||||
|
||||
|
||||
account = Eventos.Accounts.Account.registration_changeset(%Eventos.Accounts.Account{}, %{
|
||||
username: username,
|
||||
domain: nil,
|
||||
private_key: privkey,
|
||||
public_key: pubkey,
|
||||
uri: "h",
|
||||
url: "h"
|
||||
})
|
||||
|
||||
user = Eventos.Accounts.User.registration_changeset(%Eventos.Accounts.User{}, %{
|
||||
email: email,
|
||||
password: password
|
||||
})
|
||||
|
||||
|
||||
account_with_user = Ecto.Changeset.put_assoc(account, :user, user)
|
||||
|
||||
try do
|
||||
coucou = Eventos.Repo.insert!(account_with_user)
|
||||
user = find_by_email(email)
|
||||
{:ok, user}
|
||||
rescue
|
||||
e in Ecto.InvalidChangesetError ->
|
||||
Logger.debug(inspect e)
|
||||
{:error, e.changeset.changes.user.errors}
|
||||
end
|
||||
|
||||
# with {:ok, %Account{} = account} <- create_account(%{username: username, suspended: false, domain: nil, private_key: privkey, public_key: pubkey, uri: "h", url: "h"}) do
|
||||
# case create_user(%{email: email, password: password, account: account}) do
|
||||
# {:ok, %User{} = user } ->
|
||||
# {:ok, user}
|
||||
# {:error, %Ecto.Changeset{} = changeset} ->
|
||||
# {:error, changeset}
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
|
||||
@doc """
|
||||
Creates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_group(%{field: value})
|
||||
{:ok, %Group{}}
|
||||
iex> create_user(%{field: value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> create_group(%{field: bad_value})
|
||||
iex> create_user(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_group(attrs \\ %{}) do
|
||||
%Group{}
|
||||
|> Group.changeset(attrs)
|
||||
def create_user(attrs \\ %{}) do
|
||||
%User{}
|
||||
|> User.registration_changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a group.
|
||||
Updates a user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_group(group, %{field: new_value})
|
||||
{:ok, %Group{}}
|
||||
iex> update_user(user, %{field: new_value})
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> update_group(group, %{field: bad_value})
|
||||
iex> update_user(user, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_group(%Group{} = group, attrs) do
|
||||
group
|
||||
|> Group.changeset(attrs)
|
||||
def update_user(%User{} = user, attrs) do
|
||||
user
|
||||
|> User.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a Group.
|
||||
Deletes a User.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_group(group)
|
||||
{:ok, %Group{}}
|
||||
iex> delete_user(user)
|
||||
{:ok, %User{}}
|
||||
|
||||
iex> delete_group(group)
|
||||
iex> delete_user(user)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_group(%Group{} = group) do
|
||||
Repo.delete(group)
|
||||
def delete_user(%User{} = user) do
|
||||
Repo.delete(user)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking group changes.
|
||||
Returns an `%Ecto.Changeset{}` for tracking user changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_group(group)
|
||||
%Ecto.Changeset{source: %Group{}}
|
||||
iex> change_user(user)
|
||||
%Ecto.Changeset{source: %User{}}
|
||||
|
||||
"""
|
||||
def change_group(%Group{} = group) do
|
||||
Group.changeset(group, %{})
|
||||
end
|
||||
|
||||
alias Eventos.Accounts.GroupAccount
|
||||
|
||||
@doc """
|
||||
Returns the list of group_accounts.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_group_accounts()
|
||||
[%GroupAccount{}, ...]
|
||||
|
||||
"""
|
||||
def list_group_accounts do
|
||||
Repo.all(GroupAccount)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single group_account.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Group account does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_group_account!(123)
|
||||
%GroupAccount{}
|
||||
|
||||
iex> get_group_account!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_group_account!(id), do: Repo.get!(GroupAccount, id)
|
||||
|
||||
@doc """
|
||||
Creates a group_account.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_group_account(%{field: value})
|
||||
{:ok, %GroupAccount{}}
|
||||
|
||||
iex> create_group_account(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_group_account(attrs \\ %{}) do
|
||||
%GroupAccount{}
|
||||
|> GroupAccount.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a group_account.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_group_account(group_account, %{field: new_value})
|
||||
{:ok, %GroupAccount{}}
|
||||
|
||||
iex> update_group_account(group_account, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_group_account(%GroupAccount{} = group_account, attrs) do
|
||||
group_account
|
||||
|> GroupAccount.chan |