Browse Source

#13: GUI to avoid changes by unregistered users

Davide Alberani 7 years ago
parent
commit
5a31cc29ab
9 changed files with 80 additions and 26 deletions
  1. 2 1
      config/index.js
  2. 3 0
      docs/DEVELOPMENT.md
  3. 44 16
      src/App.vue
  4. 4 1
      src/Attendee.vue
  5. 6 3
      src/Group.vue
  6. 8 0
      src/Toolbar.vue
  7. 2 2
      src/User.vue
  8. 4 2
      src/main.js
  9. 7 1
      src/store.js

+ 2 - 1
config/index.js

@@ -27,7 +27,8 @@ module.exports = {
         '/login': 'http://localhost:3000',
         '/logout': '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"
     // with this option, according to the CSS-Loader README

+ 3 - 0
docs/DEVELOPMENT.md

@@ -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)
 - /#/user/ - list of all users (only visible by admins)
 - /#/user/:id - show setting for the give user ID
+- /#/settings - global setting (only visible by admins)
 
 Web server
 ----------
@@ -33,6 +34,8 @@ Web server
 - /users/:id GET - a single user
 - /users/:id PUT - update a 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
 - /logout GET - log the current user out
 

+ 44 - 16
src/App.vue

@@ -9,12 +9,12 @@
                             <div class="md-title day-info-title">
                                 <md-icon class="day-icon">today</md-icon>&nbsp;{{ day.day }}
                             </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-icon>more_vert</md-icon>
                                 </md-button>
                                 <md-menu-content>
-                                    <md-menu-item @click="openNotesDialog()">
+                                    <md-menu-item v-if="loggedInUser.isAdmin || !settings.protectDayNotes" @click="openNotesDialog()">
                                         <span>edit notes</span>
                                         <md-icon>edit</md-icon>
                                     </md-menu-item>
@@ -81,32 +81,45 @@ export default {
             return {
                 dates: datesWithGroups
             };
+        },
+
+        loggedInUser() {
+            return this.$store.state.loggedInUser;
+        },
+
+        settings() {
+            return this.$store.state.settings || {};
         }
     },
 
     beforeCreate: function() {
         this.daysUrl = this.$resource('days{/day}');
         this.daysInfoUrl = this.$resource('days{/day}/info');
+        this.settingsUrl = this.$resource('settings');
     },
 
     mounted: function() {
-        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();
+        this.fetchSettings(this.initialize);
     },
 
     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() {
             var ym = this.dateToString(this.date, true);
             this.getSummary({start: ym, end: ym});
@@ -193,6 +206,21 @@ export default {
                 this.day.notes = json.notes;
                 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();
+            });
         }
     },
 

+ 4 - 1
src/Attendee.vue

@@ -52,6 +52,9 @@ export default {
     computed: {
         loggedInUser() {
             return this.$store.state.loggedInUser;
+        },
+        settings() {
+            return this.$store.state.settings || {};
         }
     },
 
@@ -61,7 +64,7 @@ export default {
 
     methods: {
         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() {

+ 6 - 3
src/Group.vue

@@ -7,16 +7,16 @@
                     <div class="md-title group-title">
                         <md-icon class="group-icon">folder_open</md-icon>&nbsp;{{ group.group }}&nbsp;<span class="counter">{{ counter }}</span>
                     </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-icon>more_vert</md-icon>
                         </md-button>
                         <md-menu-content>
-                            <md-menu-item @click="openNotesDialog()">
+                            <md-menu-item v-if="loggedInUser.isAdmin || !settings.protectGroupNotes" @click="openNotesDialog()">
                                 <span>edit notes</span>
                                 <md-icon>edit</md-icon>
                             </md-menu-item>
-                            <md-menu-item @click="openRenameGroupDialog()">
+                            <md-menu-item v-if="loggedInUser.isAdmin || !settings.protectGroupName" @click="openRenameGroupDialog()">
                                 <span>rename group</span>
                                 <md-icon>label</md-icon>
                             </md-menu-item>
@@ -146,6 +146,9 @@ export default {
         },
         loggedInUser() {
             return this.$store.state.loggedInUser;
+        },
+        settings() {
+            return this.$store.state.settings || {};
         }
     },
 

+ 8 - 0
src/Toolbar.vue

@@ -11,6 +11,10 @@
             <router-link :to="{name: 'home'}" class="home-link">ibt2</router-link>
         </h2>
         <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-tooltip md-direction="left">list of users</md-tooltip>
                 <md-icon>people_outline</md-icon>
@@ -108,6 +112,10 @@ export default {
             this.$router.push('/user/');
         },
 
+        toSettingsPage() {
+            this.$router.push('/settings/');
+        },
+
         focusToLoginForm() {
             var that = this;
             setTimeout(function() { that.$refs.usernameInput.$el.focus(); }, 400);

+ 2 - 2
src/User.vue

@@ -17,8 +17,8 @@
                 </md-input-container>
 
                 <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-card-content>
         </md-card>
@@ -32,7 +32,7 @@ import IbtDialog from './IbtDialog.vue';
 import IbtSnackbar from './IbtSnackbar.vue';
 
 export default {
-    data () {
+    data() {
         return {
             user: {_id: null, email: '', password: null, isAdmin: false},
             password: null

+ 4 - 2
src/main.js

@@ -26,6 +26,7 @@ import store_data from './store.js';
 import App from './App';
 import User from './User';
 import Users from './Users';
+import GlobalSettings from './GlobalSettings';
 import Toolbar from './Toolbar';
 import IbtFooter from './IbtFooter';
 
@@ -41,7 +42,8 @@ var routes = [
     {path: '/day/', name: 'days', component: App},
     {path: '/day/:day', name: 'day', component: App},
     {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);
@@ -52,5 +54,5 @@ var vue = new Vue({
     store: store,
     template: '<div id="app"><toolbar /><router-view class="view"></router-view><ibt-footer /></div>',
     router: router,
-    components: { App, Toolbar, IbtFooter, Users, User }
+    components: { App, Toolbar, IbtFooter, Users, User, GlobalSettings }
 });

+ 7 - 1
src/store.js

@@ -4,14 +4,20 @@
 
 export default {
     state: {
-        loggedInUser: {username: ''}
+        loggedInUser: {username: ''},
+        settings: {}
     },
     mutations: {
         clearLoggedInUser(state, user) {
             state.loggedInUser = {username: ''};
         },
+
         setLoggedInUser(state, user) {
             state.loggedInUser = user;
+        },
+
+        updateSettings(state, settings) {
+            state.settings = settings;
         }
     }
 };