#13: GUI to avoid changes by unregistered users
This commit is contained in:
parent
cffaaf9fd4
commit
5a31cc29ab
9 changed files with 80 additions and 26 deletions
|
@ -27,7 +27,8 @@ module.exports = {
|
||||||
'/login': 'http://localhost:3000',
|
'/login': 'http://localhost:3000',
|
||||||
'/logout': 'http://localhost:3000',
|
'/logout': 'http://localhost:3000',
|
||||||
'/user': 'http://localhost:3000',
|
'/user': 'http://localhost:3000',
|
||||||
'/groups': 'http://localhost:3000'
|
'/groups': 'http://localhost:3000',
|
||||||
|
'/settings': 'http://localhost:3000'
|
||||||
},
|
},
|
||||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||||
// with this option, according to the CSS-Loader README
|
// with this option, according to the CSS-Loader README
|
||||||
|
|
|
@ -13,6 +13,7 @@ These are the paths you see in the browser (VueJS does client-side routing: no r
|
||||||
- /#/day/:day - show groups for the given date (in yyyy-mm-dd format)
|
- /#/day/:day - show groups for the given date (in yyyy-mm-dd format)
|
||||||
- /#/user/ - list of all users (only visible by admins)
|
- /#/user/ - list of all users (only visible by admins)
|
||||||
- /#/user/:id - show setting for the give user ID
|
- /#/user/:id - show setting for the give user ID
|
||||||
|
- /#/settings - global setting (only visible by admins)
|
||||||
|
|
||||||
Web server
|
Web server
|
||||||
----------
|
----------
|
||||||
|
@ -33,6 +34,8 @@ Web server
|
||||||
- /users/:id GET - a single user
|
- /users/:id GET - a single user
|
||||||
- /users/:id PUT - update a user
|
- /users/:id PUT - update a user
|
||||||
- /users/current GET - information about the currently logged in user
|
- /users/current GET - information about the currently logged in user
|
||||||
|
- /settings GET - get all global settings
|
||||||
|
- /settings POST and PUT - add one or more new settings, or update existing ones
|
||||||
- /login POST - login of a user
|
- /login POST - login of a user
|
||||||
- /logout GET - log the current user out
|
- /logout GET - log the current user out
|
||||||
|
|
||||||
|
|
60
src/App.vue
60
src/App.vue
|
@ -9,12 +9,12 @@
|
||||||
<div class="md-title day-info-title">
|
<div class="md-title day-info-title">
|
||||||
<md-icon class="day-icon">today</md-icon> {{ day.day }}
|
<md-icon class="day-icon">today</md-icon> {{ day.day }}
|
||||||
</div>
|
</div>
|
||||||
<md-menu md-align-trigger>
|
<md-menu v-if="loggedInUser.isAdmin || !settings.protectDayNotes" md-align-trigger>
|
||||||
<md-button class="md-icon-button" md-menu-trigger>
|
<md-button class="md-icon-button" md-menu-trigger>
|
||||||
<md-icon>more_vert</md-icon>
|
<md-icon>more_vert</md-icon>
|
||||||
</md-button>
|
</md-button>
|
||||||
<md-menu-content>
|
<md-menu-content>
|
||||||
<md-menu-item @click="openNotesDialog()">
|
<md-menu-item v-if="loggedInUser.isAdmin || !settings.protectDayNotes" @click="openNotesDialog()">
|
||||||
<span>edit notes</span>
|
<span>edit notes</span>
|
||||||
<md-icon>edit</md-icon>
|
<md-icon>edit</md-icon>
|
||||||
</md-menu-item>
|
</md-menu-item>
|
||||||
|
@ -81,32 +81,45 @@ export default {
|
||||||
return {
|
return {
|
||||||
dates: datesWithGroups
|
dates: datesWithGroups
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
loggedInUser() {
|
||||||
|
return this.$store.state.loggedInUser;
|
||||||
|
},
|
||||||
|
|
||||||
|
settings() {
|
||||||
|
return this.$store.state.settings || {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeCreate: function() {
|
beforeCreate: function() {
|
||||||
this.daysUrl = this.$resource('days{/day}');
|
this.daysUrl = this.$resource('days{/day}');
|
||||||
this.daysInfoUrl = this.$resource('days{/day}/info');
|
this.daysInfoUrl = this.$resource('days{/day}/info');
|
||||||
|
this.settingsUrl = this.$resource('settings');
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
var [year, month, day] = (this.$route.params.day || '').split('-');
|
this.fetchSettings(this.initialize);
|
||||||
year = parseInt(year);
|
|
||||||
month = parseInt(month) - 1;
|
|
||||||
day = parseInt(day);
|
|
||||||
if (!isNaN(year) && !isNaN(month) && !isNaN(day)) {
|
|
||||||
this.date = new Date(year, month, day);
|
|
||||||
}
|
|
||||||
if (!(this.date && !isNaN(this.date.getTime()))) {
|
|
||||||
this.date = new Date();
|
|
||||||
}
|
|
||||||
$('div.calendar span.prev').on('click', this.changeMonth);
|
|
||||||
$('div.calendar span.next').on('click', this.changeMonth);
|
|
||||||
$('div.calendar span.month').on('click', this.changeMonth);
|
|
||||||
this.reload();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
initialize() {
|
||||||
|
var [year, month, day] = (this.$route.params.day || '').split('-');
|
||||||
|
year = parseInt(year);
|
||||||
|
month = parseInt(month) - 1;
|
||||||
|
day = parseInt(day);
|
||||||
|
if (!isNaN(year) && !isNaN(month) && !isNaN(day)) {
|
||||||
|
this.date = new Date(year, month, day);
|
||||||
|
}
|
||||||
|
if (!(this.date && !isNaN(this.date.getTime()))) {
|
||||||
|
this.date = new Date();
|
||||||
|
}
|
||||||
|
$('div.calendar span.prev').on('click', this.changeMonth);
|
||||||
|
$('div.calendar span.next').on('click', this.changeMonth);
|
||||||
|
$('div.calendar span.month').on('click', this.changeMonth);
|
||||||
|
this.reload();
|
||||||
|
},
|
||||||
|
|
||||||
reload() {
|
reload() {
|
||||||
var ym = this.dateToString(this.date, true);
|
var ym = this.dateToString(this.date, true);
|
||||||
this.getSummary({start: ym, end: ym});
|
this.getSummary({start: ym, end: ym});
|
||||||
|
@ -193,6 +206,21 @@ export default {
|
||||||
this.day.notes = json.notes;
|
this.day.notes = json.notes;
|
||||||
this.reload();
|
this.reload();
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchSettings(cb) {
|
||||||
|
this.settingsUrl.get().then((response) => {
|
||||||
|
return response.json();
|
||||||
|
}, (response) => {
|
||||||
|
this.$refs.dialogObj.show({text: 'unable to fetch settings'});
|
||||||
|
}).then((json) => {
|
||||||
|
if (!json || json.error) {
|
||||||
|
this.$refs.dialogObj.show({text: 'unable to fetch settings: ' + (json && json.message) || ''});
|
||||||
|
} else {
|
||||||
|
this.$store.commit('updateSettings', json);
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,9 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
loggedInUser() {
|
loggedInUser() {
|
||||||
return this.$store.state.loggedInUser;
|
return this.$store.state.loggedInUser;
|
||||||
|
},
|
||||||
|
settings() {
|
||||||
|
return this.$store.state.settings || {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -61,7 +64,7 @@ export default {
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
isAuthorized(ownerID) {
|
isAuthorized(ownerID) {
|
||||||
return !ownerID || this.$store.state.loggedInUser.isAdmin || (this.$store.state.loggedInUser._id && this.$store.state.loggedInUser._id == ownerID);
|
return (!ownerID && !this.$store.state.settings.protectUnregistered) || this.$store.state.loggedInUser.isAdmin || (this.$store.state.loggedInUser._id && this.$store.state.loggedInUser._id == ownerID);
|
||||||
},
|
},
|
||||||
|
|
||||||
editAttendee() {
|
editAttendee() {
|
||||||
|
|
|
@ -7,16 +7,16 @@
|
||||||
<div class="md-title group-title">
|
<div class="md-title group-title">
|
||||||
<md-icon class="group-icon">folder_open</md-icon> {{ group.group }} <span class="counter">{{ counter }}</span>
|
<md-icon class="group-icon">folder_open</md-icon> {{ group.group }} <span class="counter">{{ counter }}</span>
|
||||||
</div>
|
</div>
|
||||||
<md-menu md-align-trigger>
|
<md-menu v-if="loggedInUser.isAdmin || !settings.protectGroupNotes || !settings.protectGroupName" md-align-trigger>
|
||||||
<md-button class="md-icon-button" md-menu-trigger>
|
<md-button class="md-icon-button" md-menu-trigger>
|
||||||
<md-icon>more_vert</md-icon>
|
<md-icon>more_vert</md-icon>
|
||||||
</md-button>
|
</md-button>
|
||||||
<md-menu-content>
|
<md-menu-content>
|
||||||
<md-menu-item @click="openNotesDialog()">
|
<md-menu-item v-if="loggedInUser.isAdmin || !settings.protectGroupNotes" @click="openNotesDialog()">
|
||||||
<span>edit notes</span>
|
<span>edit notes</span>
|
||||||
<md-icon>edit</md-icon>
|
<md-icon>edit</md-icon>
|
||||||
</md-menu-item>
|
</md-menu-item>
|
||||||
<md-menu-item @click="openRenameGroupDialog()">
|
<md-menu-item v-if="loggedInUser.isAdmin || !settings.protectGroupName" @click="openRenameGroupDialog()">
|
||||||
<span>rename group</span>
|
<span>rename group</span>
|
||||||
<md-icon>label</md-icon>
|
<md-icon>label</md-icon>
|
||||||
</md-menu-item>
|
</md-menu-item>
|
||||||
|
@ -146,6 +146,9 @@ export default {
|
||||||
},
|
},
|
||||||
loggedInUser() {
|
loggedInUser() {
|
||||||
return this.$store.state.loggedInUser;
|
return this.$store.state.loggedInUser;
|
||||||
|
},
|
||||||
|
settings() {
|
||||||
|
return this.$store.state.settings || {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
<router-link :to="{name: 'home'}" class="home-link">ibt2</router-link>
|
<router-link :to="{name: 'home'}" class="home-link">ibt2</router-link>
|
||||||
</h2>
|
</h2>
|
||||||
<span v-if="loggedInUser.username">
|
<span v-if="loggedInUser.username">
|
||||||
|
<md-button v-if="loggedInUser.isAdmin" id="users-icon" class="md-icon-button" @click="toSettingsPage()">
|
||||||
|
<md-tooltip md-direction="left">global settings</md-tooltip>
|
||||||
|
<md-icon>settings</md-icon>
|
||||||
|
</md-button>
|
||||||
<md-button v-if="loggedInUser.isAdmin" id="users-icon" class="md-icon-button" @click="toUsersPage()">
|
<md-button v-if="loggedInUser.isAdmin" id="users-icon" class="md-icon-button" @click="toUsersPage()">
|
||||||
<md-tooltip md-direction="left">list of users</md-tooltip>
|
<md-tooltip md-direction="left">list of users</md-tooltip>
|
||||||
<md-icon>people_outline</md-icon>
|
<md-icon>people_outline</md-icon>
|
||||||
|
@ -108,6 +112,10 @@ export default {
|
||||||
this.$router.push('/user/');
|
this.$router.push('/user/');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toSettingsPage() {
|
||||||
|
this.$router.push('/settings/');
|
||||||
|
},
|
||||||
|
|
||||||
focusToLoginForm() {
|
focusToLoginForm() {
|
||||||
var that = this;
|
var that = this;
|
||||||
setTimeout(function() { that.$refs.usernameInput.$el.focus(); }, 400);
|
setTimeout(function() { that.$refs.usernameInput.$el.focus(); }, 400);
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
|
|
||||||
<md-switch v-if="loggedInUser.isAdmin" v-model="user.isAdmin" class="md-warn">is admin</md-switch>
|
<md-switch v-if="loggedInUser.isAdmin" v-model="user.isAdmin" class="md-warn">is admin</md-switch>
|
||||||
<br />
|
|
||||||
|
|
||||||
|
<br />
|
||||||
<md-button id="save-button" class="md-raised md-primary" @click="save()">Save</md-button>
|
<md-button id="save-button" class="md-raised md-primary" @click="save()">Save</md-button>
|
||||||
</md-card-content>
|
</md-card-content>
|
||||||
</md-card>
|
</md-card>
|
||||||
|
@ -32,7 +32,7 @@ import IbtDialog from './IbtDialog.vue';
|
||||||
import IbtSnackbar from './IbtSnackbar.vue';
|
import IbtSnackbar from './IbtSnackbar.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {
|
||||||
user: {_id: null, email: '', password: null, isAdmin: false},
|
user: {_id: null, email: '', password: null, isAdmin: false},
|
||||||
password: null
|
password: null
|
||||||
|
|
|
@ -26,6 +26,7 @@ import store_data from './store.js';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import User from './User';
|
import User from './User';
|
||||||
import Users from './Users';
|
import Users from './Users';
|
||||||
|
import GlobalSettings from './GlobalSettings';
|
||||||
import Toolbar from './Toolbar';
|
import Toolbar from './Toolbar';
|
||||||
import IbtFooter from './IbtFooter';
|
import IbtFooter from './IbtFooter';
|
||||||
|
|
||||||
|
@ -41,7 +42,8 @@ var routes = [
|
||||||
{path: '/day/', name: 'days', component: App},
|
{path: '/day/', name: 'days', component: App},
|
||||||
{path: '/day/:day', name: 'day', component: App},
|
{path: '/day/:day', name: 'day', component: App},
|
||||||
{path: '/user/', name: 'users', component: Users},
|
{path: '/user/', name: 'users', component: Users},
|
||||||
{path: '/user/:id', name: 'user', component: User}
|
{path: '/user/:id', name: 'user', component: User},
|
||||||
|
{path: '/settings/', name: 'settings', component: GlobalSettings},
|
||||||
];
|
];
|
||||||
|
|
||||||
const store = new Vuex.Store(store_data);
|
const store = new Vuex.Store(store_data);
|
||||||
|
@ -52,5 +54,5 @@ var vue = new Vue({
|
||||||
store: store,
|
store: store,
|
||||||
template: '<div id="app"><toolbar /><router-view class="view"></router-view><ibt-footer /></div>',
|
template: '<div id="app"><toolbar /><router-view class="view"></router-view><ibt-footer /></div>',
|
||||||
router: router,
|
router: router,
|
||||||
components: { App, Toolbar, IbtFooter, Users, User }
|
components: { App, Toolbar, IbtFooter, Users, User, GlobalSettings }
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,14 +4,20 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {
|
state: {
|
||||||
loggedInUser: {username: ''}
|
loggedInUser: {username: ''},
|
||||||
|
settings: {}
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
clearLoggedInUser(state, user) {
|
clearLoggedInUser(state, user) {
|
||||||
state.loggedInUser = {username: ''};
|
state.loggedInUser = {username: ''};
|
||||||
},
|
},
|
||||||
|
|
||||||
setLoggedInUser(state, user) {
|
setLoggedInUser(state, user) {
|
||||||
state.loggedInUser = user;
|
state.loggedInUser = user;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateSettings(state, settings) {
|
||||||
|
state.settings = settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue