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:
parent
6b8223df43
commit
ddd2680d0d
32 changed files with 295 additions and 78 deletions
16
app/controllers/me.js
Normal file
16
app/controllers/me.js
Normal 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();
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
},
|
||||
|
||||
|
|
19
app/controllers/user/delete.js
Normal file
19
app/controllers/user/delete.js
Normal 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/');
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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/');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
17
app/controllers/user/index.js
Normal file
17
app/controllers/user/index.js
Normal 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')
|
||||
});
|
21
app/controllers/user/new.js
Normal file
21
app/controllers/user/new.js
Normal 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');
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
9
app/routes/me.js
Normal 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');
|
||||
}
|
||||
});
|
8
app/routes/user/delete.js
Normal file
8
app/routes/user/delete.js
Normal 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);
|
||||
}
|
||||
});
|
|
@ -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
8
app/routes/user/index.js
Normal 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
5
app/routes/user/new.js
Normal 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, {
|
||||
});
|
|
@ -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
20
app/templates/me.hbs
Normal 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}}
|
10
app/templates/user/delete.hbs
Normal file
10
app/templates/user/delete.hbs
Normal 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>
|
|
@ -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>
|
||||
|
|
11
app/templates/user/index.hbs
Normal file
11
app/templates/user/index.hbs
Normal 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>
|
21
app/templates/user/new.hbs
Normal file
21
app/templates/user/new.hbs
Normal 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>
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
12
tests/unit/controllers/users/delete-test.js
Normal file
12
tests/unit/controllers/users/delete-test.js
Normal 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);
|
||||
});
|
12
tests/unit/controllers/users/edit-test.js
Normal file
12
tests/unit/controllers/users/edit-test.js
Normal 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);
|
||||
});
|
12
tests/unit/controllers/users/index-test.js
Normal file
12
tests/unit/controllers/users/index-test.js
Normal 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);
|
||||
});
|
12
tests/unit/controllers/users/new-test.js
Normal file
12
tests/unit/controllers/users/new-test.js
Normal 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);
|
||||
});
|
11
tests/unit/routes/me-test.js
Normal file
11
tests/unit/routes/me-test.js
Normal 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);
|
||||
});
|
11
tests/unit/routes/user/delete-test.js
Normal file
11
tests/unit/routes/user/delete-test.js
Normal 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);
|
||||
});
|
11
tests/unit/routes/user/index-test.js
Normal file
11
tests/unit/routes/user/index-test.js
Normal 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);
|
||||
});
|
11
tests/unit/routes/user/new-test.js
Normal file
11
tests/unit/routes/user/new-test.js
Normal 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);
|
||||
});
|
2
todo.md
2
todo.md
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue