Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

Commit

Permalink
Merge branch 'develop' into feature/#582-unit-visibility-toggle-2
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickSkowronek authored May 4, 2018
2 parents c2a2c3f + 37dfbae commit b297202
Show file tree
Hide file tree
Showing 30 changed files with 153 additions and 160 deletions.
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ before_script:
- sh -e /etc/init.d/xvfb start
# required for MongoDB to have time to start up
- sleep 15
- npm install -g @angular/cli

install:
# install api and return back to root for following steps
Expand Down Expand Up @@ -76,9 +75,9 @@ script:
- cd ..
# run frontend-tests and return back to root for following steps
- cd app/webFrontend
- ng lint # run linter
# - ng test --single-run true --watch false || true # run test - many tests are broken
- ng e2e # run end-to-end-tests
- npm run lint # run linter
# - npm run test-ci || true # run test - many tests are broken
- npm run e2e # run end-to-end-tests
- sed -i 's/$TRAVIS_COMMIT/'$TRAVIS_COMMIT'/' src/app/shared/services/raven-error-handler.service.ts
- cd ../..
- travis_wait 30 .travis/build-fe.sh # build in prod mode
Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added `SnackBarService` as wrapper for `MatSnackBar`. [#574](https://github.com/h-da/geli/issues/574)
- Added new course & user API unit tests. [#654](https://github.com/h-da/geli/issues/654) [#691](https://github.com/h-da/geli/issues/691)
- Added details of courseAdmin and teacher to course detail view. on click profiles are shown.[#598] (https://github.com/h-da/geli/issues/598)
- Added small auto linting scripts to package.json [#688](https://github.com/h-da/geli/issues/688)
- Added changed size of drop down arrows for better usability. [#686] (https://github.com/h-da/geli/issues/686)

### Changed
- Refactored or slightly altered various course & user related APIs. [#654](https://github.com/h-da/geli/issues/654) [#691](https://github.com/h-da/geli/issues/691)
- Refactored the unitCreator with a forsafe user object. [#717](https://github.com/h-da/geli/pull/717)
- Removed firstname from resend activation feature and change button positioning. [#711] (https://github.com/h-da/geli/issues/711)
- Refactored register and resend activation to use geli email validator with top level domain check. [#713] (https://github.com/h-da/geli/issues/713)

### Fixed
- Fixed Course progress mechanism
- Fixed wasteful course data usage via specialized course model interfaces. [#654](https://github.com/h-da/geli/issues/654)
- Fixed a broken documentation link. [#583](https://github.com/h-da/geli/issues/583)
- Limited the first and last name to 64 characters in the registration- and edit page. [#585](https://github.com/h-da/geli/issues/585)
Expand All @@ -28,12 +34,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed notification icon spacing in the navbar for students. [#696](https://github.com/h-da/geli/issues/696)
- Repair Angular CLI code generation. [#701](https://github.com/h-da/geli/pull/701)
- Fixed `tsconfig.spec.ts` for `ng test`. [#656](https://github.com/h-da/geli/pull/656)
- Fixed `.travis.yml`. [#706](https://github.com/h-da/geli/pull/706)

### Added
- Unit visibility toggle [#582](https://github.com/h-da/geli/issues/582)

### Security
- Fixed numerous severe user related security issues. [#691](https://github.com/h-da/geli/issues/691)
- Fixed numerous severe user related security issues. [#691](https://github.com/h-da/geli/issues/691) [#709](https://github.com/h-da/geli/pull/709)
- Fixed multiple severe course related security issues. [#594](https://github.com/h-da/geli/issues/594) [#653](https://github.com/h-da/geli/issues/653) [#691](https://github.com/h-da/geli/issues/691)
- Updated the dependencies for security. [#661](https://github.com/h-da/geli/issues/661)

Expand Down
1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"test": "istanbul cover --report json node_modules/mocha/bin/_mocha",
"posttest": "gulp remap:coverage",
"lint": "gulp tslint",
"lint:fix": "tslint --fix -c ./tslint.json 'src/**/*.ts'",
"debug": "gulp debug",
"load:fixtures": "gulp load:fixtures",
"migrate": "gulp build && node ./build/src/migrate.js",
Expand Down
6 changes: 2 additions & 4 deletions api/src/controllers/AuthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ export class AuthController {
* @apiName ActivationResend
* @apiGroup Auth
*
* @apiParam {string} firstname firstname of user which activation should be resend.
* @apiParam {string} lastname lastname of user which activation should be resend.
* @apiParam {string} uid matriculation number of user which activation should be resend.
* @apiParam {string} email email the new activation should be sent to.
Expand All @@ -156,12 +155,11 @@ export class AuthController {
*/
@Post('/activationresend')
@OnUndefined(204)
async activationResend (@BodyParam('firstname') firstname: string,
@BodyParam('lastname') lastname: string,
async activationResend (@BodyParam('lastname') lastname: string,
@BodyParam('uid') uid: string,
@BodyParam('email') email: string,
@Res() response: Response) {
const user = await User.findOne({'profile.firstName': firstname, 'profile.lastName': lastname, uid: uid, role: 'student'});
const user = await User.findOne({'profile.lastName': lastname, uid: uid, role: 'student'});

if (!user) {
throw new BadRequestError(errorCodes.errorCodes.user.userNotFound.code);
Expand Down
2 changes: 1 addition & 1 deletion api/src/controllers/UnitController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export class UnitController {
// discard invalid requests
this.checkPostParam(data);
// Set current user as creator, old unit's dont have a creator
data.model.unitCreator = currentUser._id.toString();
data.model.unitCreator = currentUser._id;

return Unit.create(data.model)
.then((createdUnit) => {
Expand Down
2 changes: 1 addition & 1 deletion api/src/models/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ userSchema.methods.forUser = function (otherUser: IUser): IUserSubSafe | IUserSu
// (Or when the currentUser is an admin or targets itself.)
const editLevels: {[key: string]: number} = {
student: 0,
teacher: 1,
teacher: 0,
admin: 2,
};

Expand Down
12 changes: 10 additions & 2 deletions api/src/models/units/Unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {fileUnitSchema} from './FileUnit';
import {taskUnitSchema} from './TaskUnit';
import {IUser} from '../../../../shared/models/IUser';
import {IProgress} from '../../../../shared/models/progress/IProgress';
import {User} from '../User';

interface IUnitModel extends IUnit, mongoose.Document {
exportJSON: () => Promise<IUnit>;
Expand Down Expand Up @@ -44,8 +45,9 @@ const unitSchema = new mongoose.Schema({
type: Boolean
},
unitCreator: {
type: String
}
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
},
{
collection: 'units',
Expand Down Expand Up @@ -88,10 +90,16 @@ unitSchema.methods.calculateProgress = async function(): Promise<IUnit> {
};

unitSchema.methods.populateUnit = async function(): Promise<IUnit> {
if (this.unitCreator) {
this.unitCreator = await User.findById(this.unitCreator);
}
return this;
};

unitSchema.methods.secureData = async function(user: IUser): Promise<IUnitModel> {
if (this.unitCreator) {
this.unitCreator = User.forSafe(this.unitCreator);
}
return this;
};

Expand Down
15 changes: 5 additions & 10 deletions api/test/integration/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ describe('Auth', () => {

const res = await chai.request(app)
.post(`${BASE_URL}/activationresend`)
.send({'firstname': resendActivationUser.profile.firstName,
'lastname': resendActivationUser.profile.lastName,
.send({'lastname': resendActivationUser.profile.lastName,
'uid': resendActivationUser.uid,
'email': resendActivationUser.email })
.catch(err => err.response);
Expand All @@ -176,8 +175,7 @@ describe('Auth', () => {

const res = await chai.request(app)
.post(`${BASE_URL}/activationresend`)
.send({'firstname': resendActivationUser.profile.firstName,
'lastname': resendActivationUser.profile.lastName,
.send({'lastname': resendActivationUser.profile.lastName,
'uid': resendActivationUser.uid,
'email': resendActivationUser.email })
.catch(err => err.response);
Expand All @@ -196,8 +194,7 @@ describe('Auth', () => {

const res = await chai.request(app)
.post(`${BASE_URL}/activationresend`)
.send({'firstname': resendActivationUser.profile.firstName,
'lastname': resendActivationUser.profile.lastName,
.send({'lastname': resendActivationUser.profile.lastName,
'uid': resendActivationUser.uid,
'email': resendActivationUser.email })
.catch(err => err.response);
Expand All @@ -218,8 +215,7 @@ describe('Auth', () => {

const res = await chai.request(app)
.post(`${BASE_URL}/activationresend`)
.send({'firstname': resendActivationUser.profile.firstName,
'lastname': resendActivationUser.profile.lastName,
.send({'lastname': resendActivationUser.profile.lastName,
'uid': resendActivationUser.uid,
'email': resendActivationUser.email })
.catch(err => err.response);
Expand All @@ -236,8 +232,7 @@ describe('Auth', () => {

const res = await chai.request(app)
.post(`${BASE_URL}/activationresend`)
.send({'firstname': resendActivationUser.profile.firstName,
'lastname': resendActivationUser.profile.lastName,
.send({'lastname': resendActivationUser.profile.lastName,
'uid': resendActivationUser.uid,
'email': resendActivationUser.email })
.catch(err => err.response);
Expand Down
3 changes: 2 additions & 1 deletion api/test/integration/unit/codeKataUnit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ describe(`CodeKataUnit ${BASE_URL}`, () => {
res.status.should.be.equal(200);
res.body.name.should.equal(model.name);
res.body.description.should.equal(model.description);
res.body.unitCreator.should.equal(courseAdmin._id.toString());
res.body.unitCreator.profile.lastName.should.equal(courseAdmin.profile.lastName);
res.body.unitCreator.profile.firstName.should.equal(courseAdmin.profile.firstName);
});

it('should update a codeKata', async () => {
Expand Down
90 changes: 34 additions & 56 deletions api/test/integration/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,67 +156,61 @@ describe('User', () => {
});

describe(`PUT ${BASE_URL}`, () => {
function requestUserUpdate(currentUser: IUser, updatedUser: IUser) {
return chai.request(app)
.put(`${BASE_URL}/${updatedUser._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(currentUser)}`)
.send(updatedUser);
}

function requestUserUpdateAndCatch(currentUser: IUser, updatedUser: IUser) {
return requestUserUpdate(currentUser, updatedUser).catch(err => err.response);
}

function assertFailure(res: request.Response, status: number, name: string, message: string) {
res.status.should.be.equal(status);
res.body.name.should.be.equal(name);
res.body.message.should.be.equal(message);
}

it('should fail with bad request (revoke own admin privileges)', async () => {
const admin = await FixtureUtils.getRandomAdmin();

const updatedUser = admin;
updatedUser.role = 'teacher';
const res = await chai.request(app)
.put(`${BASE_URL}/${admin._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(admin)}`)
.send(updatedUser)
.catch(err => err.response);

res.status.should.be.equal(400);
res.body.name.should.be.equal('BadRequestError');
res.body.message.should.be.equal(errorCodes.user.cantChangeOwnRole.text);
const res = await requestUserUpdateAndCatch(admin, updatedUser);
assertFailure(res, 400, 'BadRequestError', errorCodes.user.cantChangeOwnRole.text);
});

it('should fail with bad request (email already in use)', async () => {
const admin = await FixtureUtils.getRandomAdmin();
const updatedUser = await FixtureUtils.getRandomStudent();
updatedUser.email = admin.email;

const res = await chai.request(app)
.put(`${BASE_URL}/${updatedUser._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(admin)}`)
.send(updatedUser)
.catch(err => err.response);

res.status.should.be.equal(400);
res.body.name.should.be.equal('BadRequestError');
res.body.message.should.be.equal(errorCodes.user.emailAlreadyInUse.text);
const res = await requestUserUpdateAndCatch(admin, updatedUser);
assertFailure(res, 400, 'BadRequestError', errorCodes.user.emailAlreadyInUse.text);
});

// This test is disabled because there currently is no role beneath 'admin' that is allowed to edit other users.
// Reactivate and adjust this test if such a role should become available in the future.
// (Previously teachers had permission to change some parts of any student's profile.)
/*
it('should fail changing other user\'s uid with wrong authorization (not admin)', async () => {
const teacher = await FixtureUtils.getRandomTeacher();
const updatedUser = await FixtureUtils.getRandomStudent();
updatedUser.uid = '987456';
const res = await chai.request(app)
.put(`${BASE_URL}/${updatedUser._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(teacher)}`)
.send(updatedUser)
.catch(err => err.response);

res.status.should.be.equal(403);
res.body.name.should.be.equal('ForbiddenError');
res.body.message.should.be.equal(errorCodes.user.onlyAdminsCanChangeUids.text);
const res = await requestUserUpdateAndCatch(teacher, updatedUser);
assertFailure(res, 403, 'ForbiddenError', errorCodes.user.onlyAdminsCanChangeUids.text);
});
*/

it('should fail changing other user\'s name with wrong authorization (low edit level)', async () => {
const [student, updatedUser] = await FixtureUtils.getRandomStudents(2, 2);
updatedUser.profile.firstName = 'TEST';

const res = await chai.request(app)
.put(`${BASE_URL}/${updatedUser._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(student)}`)
.send(updatedUser)
.catch(err => err.response);

res.status.should.be.equal(403);
res.body.name.should.be.equal('ForbiddenError');
res.body.message.should.be.equal(errorCodes.user.cantChangeUserWithHigherRole.text);
const res = await requestUserUpdateAndCatch(student, updatedUser);
assertFailure(res, 403, 'ForbiddenError', errorCodes.user.cantChangeUserWithHigherRole.text);
});

it('should update user base data without password', async () => {
Expand All @@ -227,11 +221,7 @@ describe('User', () => {
updatedUser.profile.lastName = 'User';
updatedUser.email = '[email protected]';

const res = await chai.request(app)
.put(`${BASE_URL}/${student._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(student)}`)
.send(updatedUser);

const res = await requestUserUpdate(student, updatedUser);
res.status.should.be.equal(200);
res.body.profile.firstName.should.be.equal('Updated');
res.body.profile.lastName.should.be.equal('User');
Expand All @@ -246,11 +236,7 @@ describe('User', () => {
updatedUser.profile.lastName = 'User';
updatedUser.email = '[email protected]';

const res = await chai.request(app)
.put(`${BASE_URL}/${student._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(student)}`)
.send(updatedUser);

const res = await requestUserUpdate(student, updatedUser);
res.status.should.be.equal(200);
res.body.profile.firstName.should.be.equal('Updated');
res.body.profile.lastName.should.be.equal('User');
Expand All @@ -265,11 +251,7 @@ describe('User', () => {
updatedUser.profile.lastName = 'User';
updatedUser.email = '[email protected]';

const res = await chai.request(app)
.put(`${BASE_URL}/${student._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(student)}`)
.send(updatedUser);

const res = await requestUserUpdate(student, updatedUser);
res.status.should.be.equal(200);
res.body.profile.firstName.should.be.equal('Updated');
res.body.profile.lastName.should.be.equal('User');
Expand All @@ -287,11 +269,7 @@ describe('User', () => {
updatedUser.profile.lastName = 'User';
updatedUser.email = '[email protected]';

const res = await chai.request(app)
.put(`${BASE_URL}/${student._id}`)
.set('Authorization', `JWT ${JwtUtils.generateToken(admin)}`)
.send(updatedUser);

const res = await requestUserUpdate(admin, updatedUser);
res.status.should.be.equal(200);
res.body.uid.should.be.equal(origUid);
res.body.profile.firstName.should.be.equal('Updated');
Expand Down
2 changes: 2 additions & 0 deletions app/webFrontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"build": "ng build --prod --sourcemaps",
"build-pr": "ng build --prod",
"test": "ng test",
"test-ci": "ng test --single-run",
"lint": "ng lint",
"lint:fix": "ng lint --fix",
"e2e": "ng e2e"
},
"private": true,
Expand Down
Loading

0 comments on commit b297202

Please sign in to comment.