1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

Add user management. Move relationship building to server side

Admins can create/edit and delete users (with all their projects etc.)
Deleting a user/project/visualization automatically deletes all its belonging
data (e.g. deleting a visualization deletes all plots).
When creating and deleting objects the relationship is (mostly) handled server
side. Only the first required relationship (e.g. when creating a new project,
the project's owner is set client-side, the rest is matched on the server).
This commit is contained in:
Markus Grigull 2016-07-11 22:03:47 +02:00
parent 6b8223df43
commit ddd2680d0d
32 changed files with 295 additions and 78 deletions

16
app/controllers/me.js Normal file
View file

@ -0,0 +1,16 @@
import Ember from 'ember';
export default Ember.Controller.extend({
isAdmin: function() {
var level = this.get('model.adminLevel');
return level >= 1;
}.property('model'),
actions: {
changeUser() {
// save the changes
var user = this.get('model');
user.save();
}
}
});

View file

@ -11,35 +11,11 @@ export default Ember.Controller.extend({
},
confirmDelete() {
// get current user object
var userId = this.get('sessionUser.user.id');
var user = this.store.peekRecord('user', userId);
// get the project
// delete the project
var project = this.get('model');
let projectId = project.get('id');
// delete the project and remove from user projects
var visualizations = project.get('visualizations');
visualizations.forEach(function(visualization) {
// destroy all plots
var plots = visualization.get('plots');
plots.forEach(function(plot) {
plot.destroyRecord();
});
visualization.destroyRecord();
});
project.destroyRecord();
// save the changes to project
var controller = this;
user.get('projects').removeObject(projectId);
user.save().then(function() {
controller.transitionToRoute('/projects');
});
this.transitionToRoute('/projects');
}
}
});

View file

@ -10,13 +10,10 @@ export default Ember.Controller.extend({
// create the visualization
var visualization = this.store.createRecord('visualization', { name: 'Visualization', project: projectId });
// the visualization must be added to the project before the project is saved, otherwise ember will set the projectId to null!
// this change will not be saved, but it is nessecary otherwise ember will omit the project's id in the post request
project.get('visualizations').pushObject(visualization);
// save the visualization and project
visualization.save().then(function() {
project.save();
});
visualization.save();
}
}
});

View file

@ -5,9 +5,8 @@ export default Ember.Controller.extend({
actions: {
newProject() {
// get current user object
var userId = this.get('sessionUser.user.id');
var user = this.store.peekRecord('user', userId);
// get current user
var user = this.get('sessionUser.user');
// create new project from properties
var properties = this.getProperties('name');
@ -16,14 +15,8 @@ export default Ember.Controller.extend({
var project = this.store.createRecord('project', properties);
var controller = this;
// save the project and user
project.save().then(function() {
// add the project to the user
user.get('projects').pushObject(project);
user.save().then(function() {
controller.transitionToRoute('/projects');
});
controller.transitionToRoute('/projects');
});
},

View file

@ -0,0 +1,19 @@
import Ember from 'ember';
export default Ember.Controller.extend({
sessionUser: Ember.inject.service('session-user'),
actions: {
cancelDelete() {
this.transitionToRoute('/user/');
},
confirmDelete() {
// delete all projects
var user = this.get('model');
user.destroyRecord();
this.transitionToRoute('/user/');
}
}
});

View file

@ -2,10 +2,18 @@ import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
changeUser() {
saveEdit() {
// save the changes
var user = this.get('model');
user.save();
var controller = this;
user.save().then(function() {
controller.transitionToRoute('/user/');
});
},
cancelEdit() {
this.transitionToRoute('/user/');
}
}
});

View file

@ -0,0 +1,17 @@
import Ember from 'ember';
export default Ember.Controller.extend({
users: function() {
var filteredUsers = this.get('model');
filteredUsers.forEach(function(user) {
// catch undefined user
if (user) {
if (user.get('id') === 'me') {
filteredUsers.removeObject(user);
}
}
});
return filteredUsers;
}.property('model.@each')
});

View file

@ -0,0 +1,21 @@
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
newUser() {
// create new user from properties
var properties = this.getProperties('username', 'password');
var user = this.store.createRecord('user', properties);
var controller = this;
user.save().then(function() {
controller.transitionToRoute('/user');
});
},
cancelNewUser() {
this.transitionToRoute('/user');
}
}
});

View file

@ -10,27 +10,12 @@ export default Ember.Controller.extend({
confirmDelete() {
// get the objects
var visualization = this.get('model');
let visualizationId = this.get('model.id');
var projectId = this.get('model.project.id');
var project = this.store.peekRecord('project', projectId);
// destroy all plots
var plots = visualization.get('plots');
plots.forEach(function(plot) {
plot.destroyRecord();
});
var visualization = this.get('model');
visualization.destroyRecord();
// delete the visualization and remove from the project
var controller = this;
project.get('visualizations').removeObject(visualizationId);
project.save().then(function() {
controller.transitionToRoute('/project/' + projectId);
});
this.transitionToRoute('/project/' + projectId);
}
}
});

View file

@ -4,6 +4,7 @@ import { hasMany } from 'ember-data/relationships';
export default Model.extend({
username: attr('string'),
password: attr('string'),
adminLevel: attr('number'),
projects: hasMany('project', { async: true }),
mail: attr('string')

View file

@ -7,6 +7,7 @@ const Router = Ember.Router.extend({
Router.map(function() {
this.route('login');
this.route('logout');
this.route('projects');
this.route('project', function() {
@ -16,9 +17,7 @@ Router.map(function() {
this.route('delete', { path: '/delete/:projectid' });
});
this.route('user', function() {
this.route('edit');
});
this.route('me');
this.route('visualization', function() {
this.route('index', { path: '/:visualizationid' });
@ -27,8 +26,13 @@ Router.map(function() {
this.route('delete', { path: '/delete/:visualizationid' });
});
this.route('user', function() {
this.route('edit', { path: '/edit/:userid' });
this.route('new');
this.route('delete', { path: '/delete/:userid' });
});
this.route('404', { path: '/*path' });
this.route('logout');
});
export default Router;

9
app/routes/me.js Normal file
View file

@ -0,0 +1,9 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model() {
// get session user
return this.store.findRecord('user', 'me');
}
});

View file

@ -0,0 +1,8 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model(params) {
return this.store.findRecord('user', params.userid);
}
});

View file

@ -2,11 +2,7 @@ import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
sessionUser: Ember.inject.service('session-user'),
model() {
// get session user
var userId = this.get('sessionUser.user.id');
return this.store.findRecord('user', userId);
model(params) {
return this.store.findRecord('user', params.userid);
}
});

8
app/routes/user/index.js Normal file
View file

@ -0,0 +1,8 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model() {
return this.store.findAll('user');
}
});

5
app/routes/user/new.js Normal file
View file

@ -0,0 +1,5 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
});

View file

@ -9,7 +9,7 @@
<ul>
<li>{{#link-to 'index'}}Home{{/link-to}}</li>
<li>{{#link-to 'projects'}}Projects{{/link-to}}</li>
<li>{{#link-to 'user.edit'}}Preferences{{/link-to}}</li>
<li>{{#link-to 'me'}}Account{{/link-to}}</li>
<li>{{#link-to 'logout'}}Logout{{/link-to}}</li>
</ul>
</div>

20
app/templates/me.hbs Normal file
View file

@ -0,0 +1,20 @@
<h1>Preferences</h1>
<form id="user-edit-form" {{action 'changeUser' on='submit'}} >
<p>
<label for="username">Username</label>
{{input id='username' value=model.username readonly=true}}
</p>
<p>
<label for="mail">Mail</label>
{{input id='mail' value=model.mail placeholder='Enter e-mail'}}
</p>
<button type="submit">Save</button>
</form>
{{#if isAdmin}}
<div>
{{#link-to 'user'}}Users{{/link-to}}
</div>
{{/if}}

View file

@ -0,0 +1,10 @@
<h1>Delete User</h1>
<p>
Are you sure you want to delete the user "{{model.username}}"?
<br />
This will also delete all projects belonging to this user!
</p>
<button {{action 'cancelDelete'}}>Cancel</button>
<button {{action 'confirmDelete'}}>Delete</button>

View file

@ -1,14 +1,14 @@
<h1>Preferences</h1>
<h1>Edit</h1>
<form id="user-edit-form" {{action 'changeUser' on='submit'}} >
<form id="user-edit-form" {{action 'saveEdit' on='submit'}} >
<p>
<label for="username">Username</label>
{{input id='username' value=model.username readonly=true}}
{{input id='username' value=model.username}}
</p>
<p>
<label for="mail">Mail</label>
{{input id='mail' value=model.mail placeholder='Enter e-mail'}}
</p>
<button type="submit">Save</button>
</form>

View file

@ -0,0 +1,11 @@
<h1>Users</h1>
{{#link-to 'user.new'}}New user{{/link-to}}
<div>
<ul>
{{#each users as |user|}}
<li>{{#link-to 'user.edit' user.id}}{{user.username}}{{/link-to}} {{#link-to 'user.delete' user.id}}X{{/link-to}}</li>
{{/each}}
</ul>
</div>

View file

@ -0,0 +1,21 @@
<h1>New user</h1>
<section id="user-new">
<form id="user-new-form" {{action 'newUser' on='submit'}} >
<p>
<label for="username">Name</label>
{{input id='username' placeholder='Enter username' value=username}}
</p>
<p>
<label for="password">Name</label>
{{input id='password' placeholder='Enter password' type='password' value=password}}
</p>
<button {{action 'cancelNewUser'}}>Cancel</button>
<button type="submit">Create</button>
{{#if errorMessage}}
<p>{{errorMessage.message}}</p>
{{/if}}
</form>
</section>

View file

@ -37,7 +37,7 @@
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.5.1",
"ember-resolver": "^2.0.3",
"loader.js": "^4.0.1",
"ember-simple-auth": "^1.1.0"
"ember-simple-auth": "^1.1.0",
"loader.js": "^4.0.1"
}
}

View file

@ -0,0 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:users/delete', 'Unit | Controller | users/delete', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View file

@ -0,0 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:users/edit', 'Unit | Controller | users/edit', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View file

@ -0,0 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:users/index', 'Unit | Controller | users/index', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View file

@ -0,0 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('controller:users/new', 'Unit | Controller | users/new', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
});

View file

@ -0,0 +1,11 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:me', 'Unit | Route | me', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View file

@ -0,0 +1,11 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:user/delete', 'Unit | Route | user/delete', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View file

@ -0,0 +1,11 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:user/index', 'Unit | Route | user/index', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View file

@ -0,0 +1,11 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:user/new', 'Unit | Route | user/new', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View file

@ -2,4 +2,4 @@
- Change password
- Create/register user
- User management
- Rename preferences into account
- Don't log out on unauthorized access (admin level lower than required)