Browse Source

permissions enforcement

Davide Alberani 7 years ago
parent
commit
9f8e7e762b
5 changed files with 176 additions and 27 deletions
  1. 11 10
      ibt2.py
  2. 26 6
      src/Attendee.vue
  3. 46 8
      src/User.vue
  4. 88 0
      src/Users.vue
  5. 5 3
      src/main.js

+ 11 - 10
ibt2.py

@@ -370,10 +370,14 @@ class UsersHandler(CollectionHandler):
     @gen.coroutine
     def get(self, id_=None, **kwargs):
         if id_:
+            if str(self.current_user_info.get('_id')) != id_ and not self.current_user_info.get('isAdmin'):
+                return self.build_error(status=401, message='insufficient permissions: must be the owner or admin')
             output = self.db.getOne(self.collection, {'_id': id_})
             if 'password' in output:
                 del output['password']
         else:
+            if not self.current_user_info.get('isAdmin'):
+                return self.build_error(status=401, message='insufficient permissions: must be an admin')
             output = {self.collection: self.db.query(self.collection, self.arguments)}
             for user in output['users']:
                 if 'password' in user:
@@ -410,19 +414,16 @@ class UsersHandler(CollectionHandler):
         self._clean_dict(data)
         if id_ is None:
             return self.build_error(status=404, message='unable to access the resource')
-        old_pwd = data.get('old_password')
-        new_pwd = data.get('new_password')
-        if old_pwd is not None:
-            del data['old_password']
-        if new_pwd is not None:
-            del data['new_password']
-            authorized, user = self.user_authorized(data['username'], old_pwd)
-            if not (authorized and self.current_user == data['username']):
-                raise InputException('not authorized to change password')
-            data['password'] = utils.hash_password(new_pwd)
         if '_id' in data:
             # Avoid overriding _id
             del data['_id']
+        if 'username' in data:
+            del data['username']
+        if 'password' in data:
+            if data['password']:
+                data['password'] = utils.hash_password(data['password'])
+            else:
+                del data['password']
         if str(self.current_user_info.get('_id')) != id_ and not self.current_user_info.get('isAdmin'):
             return self.build_error(status=401, message='insufficient permissions: must be the owner or admin')
         merged, doc = self.db.update(self.collection, {'_id': id_}, data)

+ 26 - 6
src/Attendee.vue

@@ -5,12 +5,22 @@
         <md-input-container md-inline v-if="edit">
             <md-input @keyup.enter.native="updateAttendee()" v-model="attendee.name" ref="updateAttendeeName" />
         </md-input-container>
-        <md-button class="md-icon-button md-list-action" @click="editAttendee()">
-            <md-icon>edit</md-icon>
-        </md-button>
-        <md-button class="md-icon-button md-list-action" @click="deleteAttendee()">
-            <md-icon>cancel</md-icon>
-        </md-button>
+
+        <md-menu v-if="isAuthorized(attendee.created_by)" 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="editAttendee()">
+                    <span>edit</span>
+                    <md-icon>edit</md-icon>
+                </md-menu-item>
+                <md-menu-item @click="deleteAttendee()">
+                    <span>delete</span>
+                    <md-icon>cancel</md-icon>
+                </md-menu-item>
+            </md-menu-content>
+        </md-menu>
     </md-list-item>
 </template>
 <script>
@@ -24,11 +34,21 @@ export default {
         }
     },
 
+    computed: {
+        loggedInUser() {
+            return this.$store.state.loggedInUser;
+        }
+    },
+
     beforeCreate: function() {
         this.attendeesUrl = this.$resource('attendees{/id}');
     },
 
     methods: {
+        isAuthorized(ownerID) {
+            return this.$store.state.loggedInUser.isAdmin || (this.$store.state.loggedInUser._id && this.$store.state.loggedInUser._id == ownerID);
+        },
+
         editAttendee() {
             this.edit = true;
             // FIXME: it's so wrong it hurts, but any other attempt to set the focus

+ 46 - 8
src/User.vue

@@ -1,6 +1,24 @@
 <template>
     <div id="user">
-        User {{loggedInUser}}
+        <md-card>
+            <md-card-header>
+                <span class="md-title">User: {{ user.username }}</span>
+            </md-card-header>
+            <md-card-content>
+                <md-input-container>
+                    <label>Email</label>
+                    <md-input v-model="user.email" />
+                </md-input-container>
+
+                <div class="md-body-2">Change password</div>
+                <md-input-container id="password-input" md-has-password>
+                    <label>New password</label>
+                    <md-input v-model="password" type="password" />
+                </md-input-container>
+
+                <md-button class="md-raised md-primary" @click="save()">Save</md-button>
+            </md-card-content>
+        </md-card>
     </div>
 </template>
 <script>
@@ -8,32 +26,52 @@
 export default {
     data () {
         return {
+            user: {},
+            password: null
         }
     },
 
     computed: {
-        count() {
-            return this.$store.state.count;
-        },
         loggedInUser() {
+            console.log(this.$store.state.loggedInUser);
             return this.$store.state.loggedInUser;
         }
     },
 
     beforeCreate: function() {
-        this.userUrl = this.$resource('users');
+        this.usersUrl = this.$resource('users{/id}');
     },
 
     mounted: function() {
+        this.getUser(this.$route.params.id);
     },
 
     methods: {
-    },
-
-    components: {
+        getUser(id) {
+            this.usersUrl.get({id: id}).then((response) => {
+                return response.json();
+            }, (response) => {
+                alert('getUsers: unable to get resource');
+            }).then((data) => {
+                this.user = data || {};
+            });
+        },
+        save() {
+            var user_data = {password: this.password, email: this.user.email};
+            this.usersUrl.update({id: this.user._id}, user_data).then((response) => {
+                return response.json();
+            }, (response) => {
+                alert('save: unable to get resource');
+            }).then((data) => {
+                this.user = data;
+            });
+        }
     }
 }
 </script>
 
 <style>
+#user {
+    padding: 10px;
+}
 </style>

+ 88 - 0
src/Users.vue

@@ -0,0 +1,88 @@
+<template>
+    <div id="users">
+        <md-card>
+            <md-card-header>
+                <span class="md-title">Users</span>
+            </md-card-header>
+            <md-card-content>
+                <md-table>
+                    <md-table-header>
+                        <md-table-row>
+                            <md-table-head>Username</md-table-head>
+                            <md-table-head>Email</md-table-head>
+                        </md-table-row>
+                    </md-table-header>
+                    <md-table-body>
+                        <md-table-row v-for="(user, index) in users" :key="user._id">
+                            <md-table-cell>
+                                <router-link :to="userLink(user._id)" class="md-raised md-primary">
+                                    {{user.username}}
+                                </router-link>
+                            </md-table-cell>
+                            <md-table-cell>
+                                {{user.email}}
+                            </md-table-cell>
+                        </md-table-row>
+                    </md-table-body>
+                </md-table>
+            </md-card-content>
+        </md-card>
+    </div>
+</template>
+<script>
+
+export default {
+    data () {
+        return {
+            users: []
+        }
+    },
+
+    computed: {
+        loggedInUser() {
+            return this.$store.state.loggedInUser;
+        }
+    },
+
+    beforeCreate: function() {
+        this.usersUrl = this.$resource('users{/id}');
+    },
+
+    mounted: function() {
+        this.getUsers();
+    },
+
+    methods: {
+        userLink(id) {
+            return '/user/' + id;
+        },
+
+        getUsers() {
+            this.usersUrl.get().then((response) => {
+                return response.json();
+            }, (response) => {
+                alert('getUsers: unable to get resource');
+            }).then((data) => {
+                this.users = data.users || [];
+            });
+        },
+
+        deleteUser(userId) {
+            this.usersUrl.update({id: userId}).then((response) => {
+                return response.json();
+            }, (response) => {
+                alert('deleteUser: unable to get resource');
+            }).then((data) => {
+                console.log('AAAAAAAAAAAAAAAAAAAAAAAAAAAA');
+            });
+        }
+    }
+}
+</script>
+
+<style>
+#users {
+    padding: 10px;
+}
+</style>
+

+ 5 - 3
src/main.js

@@ -12,6 +12,7 @@ import jQuery from 'jquery';
 import store_data from './store.js';
 import App from './App';
 import User from './User';
+import Users from './Users';
 import Toolbar from './Toolbar';
 
 Vue.use(Vuex);
@@ -20,10 +21,11 @@ Vue.use(VueResource);
 Vue.use(VueMaterial);
 
 var routes = [
-    {path: '/', name: 'root', component: App},
+    {path: '/', name: 'home', component: App},
     {path: '/day/', name: 'days', component: App},
     {path: '/day/:day', name: 'day', component: App},
-    {path: '/user/:user', name: 'user', component: User}
+    {path: '/user/', name: 'users', component: Users},
+    {path: '/user/:id', name: 'user', component: User}
 ];
 
 const store = new Vuex.Store(store_data);
@@ -46,5 +48,5 @@ var vue = new Vue({
     store: store,
     template: '<div id="app"><Toolbar /><router-view class="view"></router-view></div>',
     router: router,
-    components: { App, Toolbar, User }
+    components: { App, Toolbar, Users, User }
 });