More Client Fixes (#9036)

* add automatic user syncing when user._v does not match with server

* fix google signup

* fixes to user sync

* check for next cron on activity

* add comment
This commit is contained in:
Matteo Pagliazzi
2017-09-14 18:55:17 +02:00
committed by GitHub
parent 2f913666cd
commit c6881c5e30
4 changed files with 59 additions and 26 deletions

View File

@@ -130,6 +130,7 @@ export default {
this.selectedItemToBuy = item; this.selectedItemToBuy = item;
}); });
// @TODO split up this file, it's too big
// Set up Error interceptors // Set up Error interceptors
axios.interceptors.response.use((response) => { axios.interceptors.response.use((response) => {
if (this.user) { if (this.user) {
@@ -149,6 +150,39 @@ export default {
return Promise.reject(error); return Promise.reject(error);
}); });
axios.interceptors.response.use((response) => {
// Verify that the user was not updated from another browser/app/client
// If it was, sync
const url = response.config.url;
const method = response.config.method;
const isApiCall = url.indexOf('api/v3') !== -1;
const userV = response.data && response.data.userV;
if (this.isUserLoaded && isApiCall && userV) {
const oldUserV = this.user._v;
this.user._v = userV;
// Do not sync again if already syncing
const isUserSync = url.indexOf('/api/v3/user') === 0 && method === 'get';
const isTasksSync = url.indexOf('/api/v3/tasks/user') === 0 && method === 'get';
// exclude chat seen requests because with real time chat they would be too many
const isChatSeen = url.indexOf('/chat/seen') !== -1 && method === 'post';
// exclude POST /api/v3/cron because the user is synced automatically after cron runs
const isCron = url.indexOf('/api/v3/cron') === 0 && method === 'post';
// Something has changed on the user object that was not tracked here, sync the user
if (userV - oldUserV > 1 && !isCron && !isChatSeen && !isUserSync && !isTasksSync) {
Promise.all([
this.$store.dispatch('user:fetch', {forceLoad: true}),
this.$store.dispatch('tasks:fetchUserTasks', {forceLoad: true}),
]);
}
}
return response;
});
// Setup listener for title // Setup listener for title
this.$store.watch(state => state.title, (title) => { this.$store.watch(state => state.title, (title) => {
document.title = title; document.title = title;

View File

@@ -86,6 +86,7 @@ div
<script> <script>
import axios from 'axios'; import axios from 'axios';
import moment from 'moment'; import moment from 'moment';
import throttle from 'lodash/throttle';
import { shouldDo } from '../../common/script/cron'; import { shouldDo } from '../../common/script/cron';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
@@ -162,6 +163,7 @@ export default {
lastShownNotifications, lastShownNotifications,
alreadyReadNotification, alreadyReadNotification,
isRunningYesterdailies: false, isRunningYesterdailies: false,
nextCron: null,
}; };
}, },
computed: { computed: {
@@ -311,12 +313,27 @@ export default {
console.log('before first yesterDailies run, current time:', (new Date()).toString()); console.log('before first yesterDailies run, current time:', (new Date()).toString());
this.runYesterDailies(); this.runYesterDailies();
// Do not remove the event listener as it's live for the entire app lifetime
document.addEventListener('mousemove', () => this.checkNextCron());
document.addEventListener('touchstart', () => this.checkNextCron());
document.addEventListener('mousedown', () => this.checkNextCron());
document.addEventListener('keydown', () => this.checkNextCron());
}); });
}, },
methods: { methods: {
playSound (sound) { playSound (sound) {
this.$root.$emit('playSound', sound); this.$root.$emit('playSound', sound);
}, },
checkNextCron: throttle(function checkNextCron () {
console.log('checking for next cron');
if (!this.isRunningYesterdailies && this.nextCron && Date.now() > this.nextCron) {
Promise.all([
this.$store.dispatch('user:fetch', {forceLoad: true}),
this.$store.dispatch('tasks:fetchUserTasks', {forceLoad: true}),
]).then(() => this.runYesterDailies());
}
}, 1000),
scheduleNextCron () { scheduleNextCron () {
console.log('scheduling next cron (scheduleNextCron fn), current time:', (new Date()).toString()); console.log('scheduling next cron (scheduleNextCron fn), current time:', (new Date()).toString());
// Open yesterdailies modal the next time cron runs // Open yesterdailies modal the next time cron runs
@@ -336,28 +353,18 @@ export default {
console.log('next cron after edit', nextCron.toDate()); console.log('next cron after edit', nextCron.toDate());
// Setup a listener that executes 10 seconds after the next cron time // Setup a listener that executes 10 seconds after the next cron time
const nextCronIn = Number(nextCron.format('x')) - Date.now() + 10 * 1000; this.nextCron = Number(nextCron.format('x'));
this.isRunningYesterdailies = false;
console.log('next cron in', nextCronIn); console.log('finished running yesterDailies');
setTimeout(async () => {
console.log('next cron timer fired, current time:', new Date(), 'syncing...');
// Sync the user before showing the modal
await Promise.all([
this.$store.dispatch('user:fetch', {forceLoad: true}),
this.$store.dispatch('tasks:fetchUserTasks', {forceLoad: true}),
]);
console.log('next timer after syncing, running yesterDailies, current time:', (new Date()).toString());
this.runYesterDailies();
}, nextCronIn);
}, },
async runYesterDailies () { async runYesterDailies () {
console.log('running yesterdailies at, current time:', new Date(), 'needsCron:', this.user.needsCron);
console.log('isRunningYesterdailies:', this.isRunningYesterdailies, (new Date()).toString()); console.log('isRunningYesterdailies:', this.isRunningYesterdailies, (new Date()).toString());
// @TODO: Hopefully we don't need this even we load correctly // @TODO: Hopefully we don't need this even we load correctly
if (this.isRunningYesterdailies) return; if (this.isRunningYesterdailies) return;
console.log('running yesterdailies at, current time:', new Date(), 'needsCron:', this.user.needsCron);
this.isRunningYesterdailies = true;
if (!this.user.needsCron) { if (!this.user.needsCron) {
console.log('cron not needed, scheduling, current time:', (new Date()).toString()); console.log('cron not needed, scheduling, current time:', (new Date()).toString());
this.handleUserNotifications(this.user.notifications); this.handleUserNotifications(this.user.notifications);
@@ -366,7 +373,6 @@ export default {
} }
let dailys = this.$store.state.tasks.data.dailys; let dailys = this.$store.state.tasks.data.dailys;
this.isRunningYesterdailies = true;
console.log('running yesterdailies (real part), current time:', (new Date()).toString()); console.log('running yesterdailies (real part), current time:', (new Date()).toString());
let yesterDay = moment().subtract('1', 'day').startOf('day').add({ let yesterDay = moment().subtract('1', 'day').startOf('day').add({
@@ -411,7 +417,6 @@ export default {
this.handleUserNotifications(this.user.notifications); this.handleUserNotifications(this.user.notifications);
console.log('scheduling next cron after runYesterDailiesAction, current time:', (new Date()).toString()); console.log('scheduling next cron after runYesterDailiesAction, current time:', (new Date()).toString());
this.isRunningYesterdailies = false;
this.scheduleNextCron(); this.scheduleNextCron();
}, },
/* eslint-enable no-console */ /* eslint-enable no-console */

View File

@@ -19,7 +19,7 @@
button.social-button(@click='socialAuth("facebook")') button.social-button(@click='socialAuth("facebook")')
.svg-icon.social-icon(v-html="icons.facebookIcon") .svg-icon.social-icon(v-html="icons.facebookIcon")
span {{$t('signUpWithSocial', {social: 'Facebook'})}} span {{$t('signUpWithSocial', {social: 'Facebook'})}}
button.social-button(@click='socialAuth("facebook")') button.social-button(@click='socialAuth("google")')
.svg-icon.social-icon(v-html="icons.googleIcon") .svg-icon.social-icon(v-html="icons.googleIcon")
span {{$t('signUpWithSocial', {social: 'Google'})}} span {{$t('signUpWithSocial', {social: 'Google'})}}
.strike .strike

View File

@@ -10,16 +10,10 @@ module.exports = function responseHandler (req, res, next) {
if (message) response.message = message; if (message) response.message = message;
// When userV=Number (user version) query parameter is passed and a user is logged in,
// sends back the current user._v in the response so that the client
// can verify if it's the most up to date data.
// Considered part of the private API for now and not officially supported
if (user) { if (user) {
response.notifications = user.notifications.map(notification => notification.toJSON()); response.notifications = user.notifications.map(notification => notification.toJSON());
if (req.query.userV) {
response.userV = user._v; response.userV = user._v;
} }
}
res.status(status).json(response); res.status(status).json(response);
}; };