-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Server: Added API end points to manage users
- Loading branch information
Showing
6 changed files
with
144 additions
and
3 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { User } from '../../db'; | ||
import { deleteApi, getApi, patchApi, postApi } from '../../utils/testing/apiUtils'; | ||
import { beforeAllDb, afterAllTests, beforeEachDb, createUserAndSession, models } from '../../utils/testing/testUtils'; | ||
|
||
describe('api_users', function() { | ||
|
||
beforeAll(async () => { | ||
await beforeAllDb('api_users'); | ||
}); | ||
|
||
afterAll(async () => { | ||
await afterAllTests(); | ||
}); | ||
|
||
beforeEach(async () => { | ||
await beforeEachDb(); | ||
}); | ||
|
||
test('should create a user', async function() { | ||
const { session: adminSession } = await createUserAndSession(1, true); | ||
|
||
const userToSave: User = { | ||
full_name: 'Toto', | ||
email: '[email protected]', | ||
max_item_size: 1000, | ||
can_share: 0, | ||
}; | ||
|
||
await postApi(adminSession.id, 'users', userToSave); | ||
|
||
const savedUser = await models().user().loadByEmail('[email protected]'); | ||
expect(savedUser.full_name).toBe('Toto'); | ||
expect(savedUser.email).toBe('[email protected]'); | ||
expect(savedUser.can_share).toBe(0); | ||
expect(savedUser.max_item_size).toBe(1000); | ||
}); | ||
|
||
test('should patch a user', async function() { | ||
const { session: adminSession } = await createUserAndSession(1, true); | ||
const { user } = await createUserAndSession(2); | ||
|
||
await patchApi(adminSession.id, `users/${user.id}`, { | ||
max_item_size: 1000, | ||
}); | ||
|
||
const savedUser = await models().user().load(user.id); | ||
expect(savedUser.max_item_size).toBe(1000); | ||
}); | ||
|
||
test('should get a user', async function() { | ||
const { session: adminSession } = await createUserAndSession(1, true); | ||
const { user } = await createUserAndSession(2); | ||
|
||
const fetchedUser: User = await getApi(adminSession.id, `users/${user.id}`); | ||
|
||
expect(fetchedUser.id).toBe(user.id); | ||
expect(fetchedUser.email).toBe(user.email); | ||
}); | ||
|
||
test('should delete a user', async function() { | ||
const { session: adminSession } = await createUserAndSession(1, true); | ||
const { user } = await createUserAndSession(2); | ||
|
||
await deleteApi(adminSession.id, `users/${user.id}`); | ||
|
||
const loadedUser = await models().user().load(user.id); | ||
expect(loadedUser).toBeFalsy(); | ||
}); | ||
|
||
test('should list users', async function() { | ||
const { session: adminSession } = await createUserAndSession(1, true); | ||
await createUserAndSession(2); | ||
await createUserAndSession(3); | ||
|
||
const results: any = await getApi(adminSession.id, 'users'); | ||
console.info(results); | ||
expect(results.items.length).toBe(3); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { User } from '../../db'; | ||
import { bodyFields } from '../../utils/requestUtils'; | ||
import { SubPath } from '../../utils/routeUtils'; | ||
import Router from '../../utils/Router'; | ||
import { AppContext } from '../../utils/types'; | ||
import { ErrorNotFound } from '../../utils/errors'; | ||
import { AclAction } from '../../models/BaseModel'; | ||
import uuidgen from '../../utils/uuidgen'; | ||
|
||
const router = new Router(); | ||
|
||
async function fetchUser(path: SubPath, ctx: AppContext): Promise<User> { | ||
const user = await ctx.models.user().load(path.id); | ||
if (!user) throw new ErrorNotFound(`No user with ID ${path.id}`); | ||
return user; | ||
} | ||
|
||
async function postedUserFromContext(ctx: AppContext): Promise<User> { | ||
return ctx.models.user().fromApiInput(await bodyFields<any>(ctx.req)); | ||
} | ||
|
||
router.get('api/users/:id', async (path: SubPath, ctx: AppContext) => { | ||
const user = await fetchUser(path, ctx); | ||
await ctx.models.user().checkIfAllowed(ctx.owner, AclAction.Read, user); | ||
return user; | ||
}); | ||
|
||
router.post('api/users', async (_path: SubPath, ctx: AppContext) => { | ||
await ctx.models.user().checkIfAllowed(ctx.owner, AclAction.Create); | ||
const user = await postedUserFromContext(ctx); | ||
|
||
// We set a random password because it's required, but user will have to | ||
// set it by clicking on the confirmation link. | ||
user.password = uuidgen(); | ||
const output = await ctx.models.user().save(user); | ||
return ctx.models.user().toApiOutput(output); | ||
}); | ||
|
||
router.get('api/users', async (_path: SubPath, ctx: AppContext) => { | ||
await ctx.models.user().checkIfAllowed(ctx.owner, AclAction.List); | ||
|
||
return { | ||
items: await ctx.models.user().all(), | ||
has_more: false, | ||
}; | ||
}); | ||
|
||
router.del('api/users/:id', async (path: SubPath, ctx: AppContext) => { | ||
const user = await fetchUser(path, ctx); | ||
await ctx.models.user().checkIfAllowed(ctx.owner, AclAction.Delete, user); | ||
await ctx.models.user().delete(user.id); | ||
}); | ||
|
||
router.patch('api/users/:id', async (path: SubPath, ctx: AppContext) => { | ||
const user = await fetchUser(path, ctx); | ||
await ctx.models.user().checkIfAllowed(ctx.owner, AclAction.Update, user); | ||
const postedUser = await postedUserFromContext(ctx); | ||
await ctx.models.user().save({ id: user.id, ...postedUser }); | ||
}); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters