feat(streams): finalised routes and tests (integration & service) for streams

This commit is contained in:
Dimitrie Stefanescu
2020-04-08 19:32:26 +01:00
parent 94b5976bd2
commit 4ecc313eca
8 changed files with 77 additions and 40 deletions
-1
View File
@@ -17,7 +17,6 @@ exports.init = ( ) => {
// Error responses
app.use( ( err, req, res, next ) => {
debug( err )
res.status( err.status || 500 )
res.json( {
message: err.message,
+2 -2
View File
@@ -5,7 +5,7 @@ exports.up = async knex => {
await knex.raw( 'CREATE EXTENSION IF NOT EXISTS "pgcrypto"' )
await knex.schema.createTable( 'users', table => {
table.uuid( 'id' ).defaultTo( knex.raw( 'gen_random_uuid()' ) ).unique( ).primary( )
table.text( 'id' ).unique( ).primary( )
table.text( 'username' ).unique( ).notNullable( )
table.timestamp( 'created_at' ).defaultTo( knex.fn.now( ) )
table.text( 'name' ).notNullable( )
@@ -18,7 +18,7 @@ exports.up = async knex => {
await knex.schema.createTable( 'api_token', table => {
table.text( 'id' ).unique( ).primary( )
table.text( 'token_digest' ).unique( )
table.uuid( 'owner_id' ).references( 'id' ).inTable( 'users' ).notNullable( )
table.text( 'owner_id' ).references( 'id' ).inTable( 'users' ).notNullable( )
table.text( 'name' )
table.text( 'last_chars' )
table.specificType( 'scopes', 'text[]' )
+9 -9
View File
@@ -7,11 +7,11 @@ exports.up = async knex => {
// Streams Table
await knex.schema.createTable( 'streams', table => {
table.uuid( 'id' ).defaultTo( knex.raw( 'gen_random_uuid()' ) ).unique( ).primary( )
table.text( 'id' ).unique( ).primary( )
table.text( 'name' )
table.text( 'description' )
table.boolean( 'isPublic' ).defaultTo( true )
table.uuid( 'cloned_from' ).references( 'id' ).inTable( 'streams' )
table.text( 'cloned_from' ).references( 'id' ).inTable( 'streams' )
table.timestamp( 'created_at' ).defaultTo( knex.fn.now( ) )
table.timestamp( 'updated_at' ).defaultTo( knex.fn.now( ) )
// table.unique( [ 'owner_id', 'name' ] )
@@ -28,8 +28,8 @@ exports.up = async knex => {
` )
await knex.schema.createTable( 'stream_acl', table => {
table.uuid( 'user_id' ).references( 'id' ).inTable( 'users' ).notNullable( )
table.uuid( 'resource_id' ).references( 'id' ).inTable( 'streams' ).notNullable( )
table.text( 'user_id' ).references( 'id' ).inTable( 'users' ).notNullable( )
table.text( 'resource_id' ).references( 'id' ).inTable( 'streams' ).notNullable( )
table.primary( [ 'user_id', 'resource_id' ] )
table.unique( [ 'user_id', 'resource_id' ] )
table.specificType( 'role', 'speckle_acl_role_type' ).defaultTo( 'write' )
@@ -41,7 +41,7 @@ exports.up = async knex => {
table.text( 'speckle_type' ).defaultTo( 'Base' ).notNullable( )
table.text( 'applicationId' )
table.jsonb( 'data' )
table.uuid( 'author' ).references( 'id' ).inTable( 'users' )
table.text( 'author' ).references( 'id' ).inTable( 'users' )
table.timestamp( 'created_at' ).defaultTo( knex.fn.now( ) )
table.index( [ 'speckle_type' ], 'type_index' )
} )
@@ -72,8 +72,8 @@ exports.up = async knex => {
// Reference table. A reference can be a branch or a tag.
await knex.schema.createTable( 'references', table => {
table.uuid( 'id' ).defaultTo( knex.raw( 'gen_random_uuid()' ) ).unique( ).primary( )
table.uuid( 'stream_id' ).references( 'id' ).inTable( 'streams' ).notNullable( )
table.uuid( 'author' ).references( 'id' ).inTable( 'users' )
table.text( 'stream_id' ).references( 'id' ).inTable( 'streams' ).notNullable( )
table.text( 'author' ).references( 'id' ).inTable( 'users' )
table.text( 'name' )
table.specificType( 'type', 'speckle_reference_type' ).defaultTo( 'branch' )
table.text( 'description' )
@@ -95,12 +95,12 @@ exports.up = async knex => {
// Flat table to store all commits to this stream, regardless of branch.
// Optional, might be removed as you can get all the commits from each branch...
await knex.schema.createTable( 'stream_commits', table => {
table.uuid( 'stream_id' ).references( 'id' ).inTable( 'streams' ).notNullable( )
table.text( 'stream_id' ).references( 'id' ).inTable( 'streams' ).notNullable( )
table.text( 'commit_id' ).references( 'hash' ).inTable( 'objects' ).notNullable( )
} )
await knex.schema.createTable( 'user_commits', table => {
table.uuid( 'owner_id' ).references( 'id' ).inTable( 'users' ).notNullable( )
table.text( 'owner_id' ).references( 'id' ).inTable( 'users' ).notNullable( )
table.text( 'commit_id' ).references( 'hash' ).inTable( 'objects' )
} )
}
+18 -7
View File
@@ -1,12 +1,16 @@
'use strict'
const debug = require( 'debug' )( 'speckle:test' )
const { getStream, createStream, updateStream, grantPermissionsStream, revokePermissionsStream } = require( './services' )
const { getUserStreams, getStreamUsers, getStream, createStream, updateStream, grantPermissionsStream, revokePermissionsStream } = require( './services' )
module.exports = {
getStreams: async ( req, res, next ) => {
res.status( 418 ).send( { todo: true } )
next( )
try {
let streams = await getUserStreams( req.user.id )
res.status( 200 ).send( streams )
} catch ( err ) {
next( err )
}
},
getStream: async ( req, res, next ) => {
@@ -45,18 +49,23 @@ module.exports = {
grantPermissions: async ( req, res, next ) => {
try {
await grantPermissionsStream( req.params.resourceId, req.body.id, req.body.role )
await grantPermissionsStream( req.params.resourceId, req.body.id, req.body.role || 'read' )
res.status( 201 ).send( { success: true } )
req.eventData = { id: req.params.resourceId, userId: req.body.id }
next( )
} catch ( err ) {
next( err )
}
},
revokePermissions: async ( req, res, next ) => {
try {
await revokePermissionsStream( req.params.resourceId, req.body.id )
res.status( 200 ).send( { success: true } )
req.eventData = { id: req.params.resourceId, userId: req.body.id }
next( )
} catch ( err ) {
next( err )
}
@@ -64,8 +73,10 @@ module.exports = {
getStreamUsers: async ( req, res, next ) => {
try {
let users = await getStreamUsers( req.params.resourceId )
res.status( 200 ).send( users )
} catch ( err ) {
console.log( err )
next( err )
}
}
+3 -1
View File
@@ -52,4 +52,6 @@ streams.delete(
authorize( 'stream_acl', 'streams', 'owner' ),
revokePermissions,
announce( 'stream-deleted', 'user' )
)
)
// console.log( streams.stack )
+10 -4
View File
@@ -1,5 +1,5 @@
'use strict'
const crs = require( 'crypto-random-string' )
const root = require( 'app-root-path' )
const knex = require( `${root}/db/knex` )
@@ -7,11 +7,11 @@ const Streams = ( ) => knex( 'streams' )
const Acl = ( ) => knex( 'stream_acl' )
module.exports = {
createStream: async ( stream, ownerId ) => {
delete stream.id
delete stream.created_at
stream.updated_at = knex.fn.now( )
stream.id = crs( { length: 10 } )
let [ res ] = await Streams( ).returning( 'id' ).insert( stream )
await Acl( ).insert( { user_id: ownerId, resource_id: res, role: 'owner' } )
@@ -62,7 +62,7 @@ module.exports = {
throw new Error( 'not implemented' )
},
getStreamsUser: async ( userId, offset, limit ) => {
getUserStreams: async ( userId, offset, limit ) => {
offset = offset || 0
limit = limit || 100
@@ -70,4 +70,10 @@ module.exports = {
.rightJoin( 'streams', { 'streams.id': 'stream_acl.resource_id' } )
.limit( limit ).offset( offset )
},
getStreamUsers: async ( streamId ) => {
return Acl( ).where( { resource_id: streamId } )
.rightJoin( 'users', { 'users.id': 'stream_acl.user_id' } )
.select( 'role', 'username', 'name', 'id' )
}
}
+34 -15
View File
@@ -11,7 +11,7 @@ chai.use( chaiHttp )
const { createUser, createToken, revokeToken, revokeTokenById, validateToken, getUserTokens } = require( '../users/services' )
const { createStream, getStream, updateStream, deleteStream, getStreamsUser, grantPermissionsStream, revokePermissionsStream } = require( '../streams/services' )
const { createStream, getStream, updateStream, deleteStream, getUserStreams, getStreamUsers, grantPermissionsStream, revokePermissionsStream } = require( '../streams/services' )
describe( 'Streams', ( ) => {
@@ -68,7 +68,7 @@ describe( 'Streams', ( ) => {
} )
it( 'Should get all streams for a user', async ( ) => {
let all = await getStreamsUser( userOne.id )
let all = await getUserStreams( userOne.id )
expect( all ).to.have.lengthOf( 2 )
} )
} )
@@ -91,15 +91,22 @@ describe( 'Streams', ( ) => {
} )
it( 'Stream should show up in the other users` list', async ( ) => {
let userTwoStreams = await getStreamsUser( userTwo.id )
let userTwoStreams = await getUserStreams( userTwo.id )
expect( userTwoStreams ).to.have.lengthOf( 1 )
expect( userTwoStreams[ 0 ] ).to.have.property( 'role' )
expect( userTwoStreams[ 0 ].role ).to.equal( 'write' )
} )
it( 'Should get the users with access to a stream', async ( ) => {
let users = await getStreamUsers( testStream.id )
expect( users ).to.have.lengthOf( 2 )
expect( users[ 0 ] ).to.not.have.property( 'email' )
expect( users[ 0 ] ).to.have.property( 'id' )
} )
it( 'Should revoke permissions on stream', async ( ) => {
await revokePermissionsStream( testStream.id, userTwo.id )
let userTwoStreams = await getStreamsUser( userTwo.id )
let userTwoStreams = await getUserStreams( userTwo.id )
expect( userTwoStreams ).to.have.lengthOf( 0 )
} )
@@ -112,14 +119,14 @@ describe( 'Streams', ( ) => {
}
} )
it( '🤔 DUBIOUS: A stream should not have more than one owner', async ( ) => {
it( '🤔 DUBIOUS DESIGN DECISION: A stream should not have more than one owner', async ( ) => {
let newStream = { name: 'XXX' }
newStream.id = await createStream( newStream, userOne.id )
await grantPermissionsStream( newStream.id, userTwo.id, 'owner' )
let usrStreams1 = await getStreamsUser( userOne.id )
let usrStreams1 = await getUserStreams( userOne.id )
let s1 = usrStreams1.find( s => s.name === 'XXX' )
let usrStreams2 = await getStreamsUser( userTwo.id )
let usrStreams2 = await getUserStreams( userTwo.id )
let s2 = usrStreams2.find( s => s.name === 'XXX' )
expect( s1.role ).to.not.equal( 'owner' )
@@ -174,6 +181,12 @@ describe( 'Streams', ( ) => {
expect( res.body ).to.have.property( 'name' )
} )
it( 'Should get the all the streams of an user', async ( ) => {
const res = await chai.request( app ).get( `/streams` ).set( 'Authorization', `Bearer ${tokenA}` )
expect( res ).to.have.status( 200 )
expect( res.body ).to.have.lengthOf( 2 )
} )
it( 'Should get a public stream, even if user is anonymous', async ( ) => {
const res = await chai.request( app ).get( `/streams/${publicStream.id}` )
expect( res ).to.have.status( 200 )
@@ -204,27 +217,33 @@ describe( 'Streams', ( ) => {
} )
it( 'Should grant permissions on a stream', async ( ) => {
const shareRes = await chai.request( app ).post( `/streams/users/${privateStream.id}` ).send( { id: userB.id, role: 'read' } ).set( 'Authorization', `Bearer ${tokenA}` )
console.log(shareRes)
expect( shareRes ).to.have.status( 200 )
const shareRes = await chai.request( app ).post( `/streams/${privateStream.id}/users` ).send( { id: userB.id, role: 'read' } ).set( 'Authorization', `Bearer ${tokenA}` )
expect( shareRes ).to.have.status( 201 )
const userBRes = await chai.request( app ).get( `/streams/${privateStream.id}` ).set( 'Authorization', `Bearer ${tokenB}` )
console.log(userBRes.status)
expect( userBRes ).to.have.status( 200 )
expect( userBRes.body ).to.have.property( 'name' )
expect( userBRes.body ).to.have.property( 'description' )
} )
it( 'Should revoke permissions on a stream', async ( ) => {
assert.fail( )
it( 'Should get all users with access to a stream', async ( ) => {
const userRes = await chai.request( app ).get( `/streams/${privateStream.id}/users` ).set( 'Authorization', `Bearer ${tokenB}` )
expect( userRes ).to.have.status( 200 )
expect( userRes.body ).to.have.lengthOf( 2 )
} )
it( 'Should revoke permissions on a stream', async ( ) => {
const revokeRes = await chai.request( app ).delete( `/streams/${privateStream.id}/users` ).send( { id: userB.id, role: 'read' } ).set( 'Authorization', `Bearer ${tokenA}` )
expect( revokeRes ).to.have.status( 200 )
const userBRes = await chai.request( app ).get( `/streams/${privateStream.id}` ).set( 'Authorization', `Bearer ${tokenB}` )
expect( userBRes ).to.have.status( 401 )
} )
it( 'Should delete a stream', async ( ) => {
assert.fail( 'Not implemented yet.' )
} )
} )
} )
+1 -1
View File
@@ -9,7 +9,7 @@ const Keys = ( ) => knex( 'api_token' )
module.exports = {
createUser: async ( user ) => {
delete user.id
user.id = crs( { length: 10 } )
if ( user.password ) {
user.password_digest = await bcrypt.hash( user.password, 10 )