permissions enforcement
This commit is contained in:
parent
7be6ab388a
commit
9f8e7e762b
5 changed files with 176 additions and 27 deletions
21
ibt2.py
21
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)
|
||||
|
|
|
@ -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
|
||||
|
|
54
src/User.vue
54
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
src/Users.vue
Normal file
88
src/Users.vue
Normal file
|
@ -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>
|
||||
|
|
@ -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 }
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue