feat(streams): finalised routes and tests (integration & service) for streams
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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[]' )
|
||||
|
||||
@@ -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' )
|
||||
} )
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,6 @@ streams.delete(
|
||||
authorize( 'stream_acl', 'streams', 'owner' ),
|
||||
revokePermissions,
|
||||
announce( 'stream-deleted', 'user' )
|
||||
)
|
||||
)
|
||||
|
||||
// console.log( streams.stack )
|
||||
@@ -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' )
|
||||
}
|
||||
}
|
||||
@@ -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.' )
|
||||
} )
|
||||
|
||||
|
||||
|
||||
} )
|
||||
|
||||
} )
|
||||
@@ -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 )
|
||||
|
||||
Reference in New Issue
Block a user