@@ -7,3 +7,4 @@ charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
spaces_around_brackets = both
|
||||
|
||||
+41
-8
@@ -7,13 +7,46 @@
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 11
|
||||
},
|
||||
"ignorePatterns": [ "modules/*/tests/*", "node_modules/*", "frontend/*"],
|
||||
"ignorePatterns": [
|
||||
"modules/*/tests/*",
|
||||
"node_modules/*",
|
||||
"frontend/*"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-spacing": [ 2, { "before": true, "after": true } ],
|
||||
"array-bracket-spacing": [ 2, "always" ],
|
||||
"block-spacing": [ 2, "always" ],
|
||||
"camelcase": [ 1, { "properties": "always" } ],
|
||||
"space-in-parens": [ 2, "always" ],
|
||||
"keyword-spacing": 2
|
||||
"arrow-spacing": [
|
||||
2,
|
||||
{
|
||||
"before": true,
|
||||
"after": true
|
||||
}
|
||||
],
|
||||
"array-bracket-spacing": [
|
||||
2,
|
||||
"always"
|
||||
],
|
||||
"block-spacing": [
|
||||
2,
|
||||
"always"
|
||||
],
|
||||
"camelcase": [
|
||||
1,
|
||||
{
|
||||
"properties": "always"
|
||||
}
|
||||
],
|
||||
"space-in-parens": [
|
||||
2,
|
||||
"always"
|
||||
],
|
||||
"keyword-spacing": 2,
|
||||
"semi": "off",
|
||||
"indent": [
|
||||
"error",
|
||||
2
|
||||
],
|
||||
"padded-blocks": [
|
||||
"error",
|
||||
"never"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ module.exports = {
|
||||
Stream: {
|
||||
|
||||
async branches( parent, args, context, info ) {
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
let { items, cursor, totalCount } = await getBranchesByStreamId( { streamId: parent.id, limit: args.limit, cursor: args.cursor } )
|
||||
|
||||
return { totalCount, cursor, items }
|
||||
|
||||
@@ -32,6 +32,8 @@ module.exports = {
|
||||
Stream: {
|
||||
|
||||
async commits( parent, args, context, info ) {
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
let { commits: items, cursor } = await getCommitsByStreamId( { streamId: parent.id, limit: args.limit, cursor: args.cursor } )
|
||||
let totalCount = await getCommitsTotalCountByStreamId( { streamId: parent.id } )
|
||||
|
||||
@@ -47,9 +49,10 @@ module.exports = {
|
||||
User: {
|
||||
|
||||
async commits( parent, args, context, info ) {
|
||||
|
||||
let publicOnly = context.userId !== parent.id
|
||||
let totalCount = await getCommitsTotalCountByUserId( { userId: parent.id } )
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
let { commits: items, cursor } = await getCommitsByUserId( { userId: parent.id, limit: args.limit, cursor: args.cursor, publicOnly } )
|
||||
|
||||
return { items, cursor, totalCount }
|
||||
@@ -58,6 +61,8 @@ module.exports = {
|
||||
},
|
||||
Branch: {
|
||||
async commits( parent, args, context, info ) {
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
let { commits, cursor } = await getCommitsByBranchId( { branchId: parent.id, limit: args.limit, cursor: args.cursor } )
|
||||
let totalCount = await getCommitsTotalCountByBranchId( { branchId: parent.id } )
|
||||
|
||||
|
||||
@@ -22,6 +22,17 @@ module.exports = {
|
||||
|
||||
let stream = await getStream( { streamId: args.id } )
|
||||
return stream
|
||||
},
|
||||
async streams( parent, args, context, info ) {
|
||||
await validateScopes( context.scopes, 'streams:read' )
|
||||
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
|
||||
let totalCount = await getUserStreamsCount( {userId: context.userId, publicOnly: false, searchQuery: args.query} )
|
||||
|
||||
let {cursor, streams} = await getUserStreams( {userId: context.userId, limit: args.limit, cursor: args.cursor, publicOnly: false, searchQuery: args.query} )
|
||||
return {totalCount, cursor: cursor, items: streams}
|
||||
}
|
||||
},
|
||||
Stream: {
|
||||
@@ -35,7 +46,9 @@ module.exports = {
|
||||
User: {
|
||||
|
||||
async streams( parent, args, context, info ) {
|
||||
// Return only the user's public streams if parent.id !== context.userId
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
// Return only the user's public streams if parent.id !== context.userId
|
||||
let publicOnly = parent.id !== context.userId
|
||||
let totalCount = await getUserStreamsCount( { userId: parent.id, publicOnly } )
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict'
|
||||
const appRoot = require( 'app-root-path' )
|
||||
const { ApolloError, AuthenticationError, UserInputError } = require( 'apollo-server-express' )
|
||||
const { createUser, getUser, getUserByEmail, getUserRole, updateUser, deleteUser, validatePasssword } = require( '../../services/users' )
|
||||
const { createUser, getUser, getUserByEmail, getUserRole, updateUser, deleteUser, searchUsers, validatePasssword } = require( '../../services/users' )
|
||||
const { createPersonalAccessToken, createAppToken, revokeToken, revokeTokenById, validateToken, getUserTokens } = require( '../../services/tokens' )
|
||||
const { validateServerRole, validateScopes, authorizeResolver } = require( `${appRoot}/modules/shared` )
|
||||
const setupCheck = require( `${appRoot}/setupcheck` )
|
||||
@@ -10,12 +10,11 @@ const zxcvbn = require( 'zxcvbn' )
|
||||
module.exports = {
|
||||
Query: {
|
||||
|
||||
async _( ) {
|
||||
async _() {
|
||||
return `Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn.`
|
||||
},
|
||||
|
||||
async user( parent, args, context, info ) {
|
||||
|
||||
await validateServerRole( context, 'server:user' )
|
||||
|
||||
if ( !args.id )
|
||||
@@ -30,6 +29,22 @@ module.exports = {
|
||||
return await getUser( args.id || context.userId )
|
||||
},
|
||||
|
||||
async userSearch( parent, args, context, info ) {
|
||||
await validateServerRole( context, 'server:user' )
|
||||
await validateScopes( context.scopes, 'profile:read' )
|
||||
await validateScopes( context.scopes, 'users:read' )
|
||||
|
||||
if ( args.query.length < 3 )
|
||||
throw new UserInputError( 'Search query must be at least 3 carachters.' )
|
||||
|
||||
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 items, please use pagination.' )
|
||||
|
||||
let {cursor, users} = await searchUsers( args.query, args.limit, args.cursor )
|
||||
return {cursor: cursor, items: users}
|
||||
},
|
||||
|
||||
async userPwdStrength( parent, args, context, info ) {
|
||||
let res = zxcvbn( args.pwd )
|
||||
return { score: res.score, feedback: res.feedback }
|
||||
@@ -64,6 +79,8 @@ module.exports = {
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
Mutation: {
|
||||
async userEdit( parent, args, context, info ) {
|
||||
await validateServerRole( context, 'server:user' )
|
||||
@@ -71,4 +88,4 @@ module.exports = {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
extend type Stream {
|
||||
commits( limit: Int! = 20, cursor: String ): CommitCollection
|
||||
commits( limit: Int! = 25, cursor: String ): CommitCollection
|
||||
commit( id: String! ): Commit
|
||||
branches( limit: Int! = 100, cursor: String ): BranchCollection
|
||||
branches( limit: Int! = 25, cursor: String ): BranchCollection
|
||||
branch( name: String! ): Branch
|
||||
}
|
||||
|
||||
extend type User {
|
||||
commits( limit: Int! = 20, cursor: String ): CommitCollectionUser
|
||||
commits( limit: Int! = 25, cursor: String ): CommitCollectionUser
|
||||
}
|
||||
|
||||
type Branch {
|
||||
@@ -14,7 +14,7 @@ type Branch {
|
||||
name: String!
|
||||
author: User!
|
||||
description: String!
|
||||
commits( limit: Int! = 20, cursor: String ): CommitCollection
|
||||
commits( limit: Int! = 25, cursor: String ): CommitCollection
|
||||
}
|
||||
|
||||
type Commit {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
extend type Query {
|
||||
stream( id: String! ): Stream
|
||||
"""
|
||||
All the streams of the current user, pass in the `query` parameter to seach by name, description or ID.
|
||||
"""
|
||||
streams( query: String!, limit: Int! = 25, cursor: String ): StreamCollection
|
||||
}
|
||||
|
||||
type Stream {
|
||||
@@ -16,7 +20,7 @@ extend type User {
|
||||
"""
|
||||
All the streams that a user has access to.
|
||||
"""
|
||||
streams( limit: Int! = 20, cursor: String ): StreamCollectionUser
|
||||
streams( limit: Int! = 25, cursor: String ): StreamCollection
|
||||
}
|
||||
|
||||
type StreamCollaborator {
|
||||
@@ -25,12 +29,13 @@ type StreamCollaborator {
|
||||
role: String!
|
||||
}
|
||||
|
||||
type StreamCollectionUser {
|
||||
type StreamCollection {
|
||||
totalCount: Int!
|
||||
cursor: String
|
||||
items: [ Stream ]
|
||||
}
|
||||
|
||||
|
||||
extend type Mutation {
|
||||
"""
|
||||
Creates a new stream.
|
||||
|
||||
@@ -3,6 +3,7 @@ extend type Query {
|
||||
Gets the profile of a user. If no id argument is provided, will return the current authenticated user's profile (as extracted from the authorization header).
|
||||
"""
|
||||
user( id: String ): User
|
||||
userSearch( query: String!, limit: Int! = 25, cursor: String ): UserSearchResultCollection
|
||||
userPwdStrength( pwd: String! ): JSONObject
|
||||
}
|
||||
|
||||
@@ -22,6 +23,21 @@ type User {
|
||||
role: String
|
||||
}
|
||||
|
||||
type UserSearchResultCollection {
|
||||
cursor: String
|
||||
items: [ UserSearchResult ]
|
||||
}
|
||||
|
||||
type UserSearchResult {
|
||||
id: String!
|
||||
username: String
|
||||
name: String
|
||||
bio: String
|
||||
company: String
|
||||
avatar: String
|
||||
verified: Boolean
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
"""
|
||||
Edits a user's profile.
|
||||
|
||||
@@ -6,50 +6,50 @@ exports.up = async knex => {
|
||||
debug( 'Setting up core module scopes.' )
|
||||
|
||||
let coreModuleScopes = [ {
|
||||
name: 'server:setup',
|
||||
description: 'Edit server information.'
|
||||
},
|
||||
{
|
||||
name: 'tokens:read',
|
||||
description: `Access your api tokens.`
|
||||
},
|
||||
{
|
||||
name: 'tokens:write',
|
||||
description: `Create and delete api tokens on your behalf.`
|
||||
},
|
||||
{
|
||||
name: 'apps:authorize',
|
||||
description: 'Grant third party applications access rights on your behalf to the api.'
|
||||
},
|
||||
{
|
||||
name: 'apps:create',
|
||||
description: 'Register a third party application.'
|
||||
},
|
||||
{
|
||||
name: 'streams:read',
|
||||
description: 'Read your streams & and any associated information (branches, tags, comments, objects, etc.)'
|
||||
},
|
||||
{
|
||||
name: 'streams:write',
|
||||
description: 'Create streams on your behalf and read your streams & any associated information (any associated information (branches, tags, comments, objects, etc.)'
|
||||
},
|
||||
{
|
||||
name: 'profile:read',
|
||||
description: `Read your profile information`
|
||||
},
|
||||
{
|
||||
name: 'profile:email',
|
||||
description: `Access your email.`
|
||||
},
|
||||
name: 'server:setup',
|
||||
description: 'Edit server information.'
|
||||
},
|
||||
{
|
||||
name: 'tokens:read',
|
||||
description: `Access your api tokens.`
|
||||
},
|
||||
{
|
||||
name: 'tokens:write',
|
||||
description: `Create and delete api tokens on your behalf.`
|
||||
},
|
||||
{
|
||||
name: 'apps:authorize',
|
||||
description: 'Grant third party applications access rights on your behalf to the api.'
|
||||
},
|
||||
{
|
||||
name: 'apps:create',
|
||||
description: 'Register a third party application.'
|
||||
},
|
||||
{
|
||||
name: 'streams:read',
|
||||
description: 'Read your streams & and any associated information (branches, tags, comments, objects, etc.)'
|
||||
},
|
||||
{
|
||||
name: 'streams:write',
|
||||
description: 'Create streams on your behalf and read your streams & any associated information (any associated information (branches, tags, comments, objects, etc.)'
|
||||
},
|
||||
{
|
||||
name: 'profile:read',
|
||||
description: `Read your profile information`
|
||||
},
|
||||
{
|
||||
name: 'profile:email',
|
||||
description: `Access your email.`
|
||||
},
|
||||
|
||||
{
|
||||
name: 'users:read',
|
||||
description: `Read other users' profile on your behalf.`
|
||||
},
|
||||
{
|
||||
name: 'users:email',
|
||||
description: 'Access the emails of other users.'
|
||||
}
|
||||
{
|
||||
name: 'users:read',
|
||||
description: `Read other users' profile on your behalf.`
|
||||
},
|
||||
{
|
||||
name: 'users:email',
|
||||
description: 'Access the emails of other users.'
|
||||
}
|
||||
]
|
||||
|
||||
await knex( 'scopes' ).insert( coreModuleScopes )
|
||||
|
||||
@@ -10,7 +10,6 @@ const BranchCommits = ( ) => knex( 'branch_commits' )
|
||||
module.exports = {
|
||||
|
||||
async createBranch( { name, description, streamId, authorId } ) {
|
||||
|
||||
let branch = {}
|
||||
branch.id = crs( { length: 10 } )
|
||||
branch.streamId = streamId
|
||||
@@ -32,7 +31,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
async getBranchesByStreamId( { streamId, limit, cursor } ) {
|
||||
limit = limit || 100
|
||||
limit = limit || 25
|
||||
let query = Branches( ).select( '*' ).where( { streamId: streamId } )
|
||||
|
||||
if ( cursor )
|
||||
|
||||
@@ -15,7 +15,6 @@ const { getBranchesByStreamId, getBranchByNameAndStreamId } = require( './branch
|
||||
module.exports = {
|
||||
|
||||
async createCommitByBranchId( { streamId, branchId, objectId, authorId, message, previousCommitIds } ) {
|
||||
|
||||
// Create main table entry
|
||||
let [ id ] = await Commits( ).returning( 'id' ).insert( {
|
||||
id: crs( { length: 10 } ),
|
||||
@@ -84,7 +83,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
async getCommitsByBranchId( { branchId, limit, cursor } ) {
|
||||
limit = limit || 20
|
||||
limit = limit || 25
|
||||
let query = BranchCommits( ).columns( [ { id: 'commitId' }, 'message', 'referencedObject', { authorName: 'name' }, { authorId: 'users.id' }, 'commits.createdAt' ] ).select( )
|
||||
.join( 'commits', 'commits.id', 'branch_commits.commitId' )
|
||||
.join( 'users', 'commits.author', 'users.id' )
|
||||
@@ -124,7 +123,7 @@ module.exports = {
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
async getCommitsByStreamId( { streamId, limit, cursor } ) {
|
||||
limit = limit || 20
|
||||
limit = limit || 25
|
||||
let query = StreamCommits( )
|
||||
.columns( [ { id: 'commitId' }, 'message', 'referencedObject', { authorName: 'name' }, { authorId: 'users.id' }, 'commits.createdAt' ] ).select( )
|
||||
.join( 'commits', 'commits.id', 'stream_commits.commitId' )
|
||||
@@ -142,15 +141,15 @@ module.exports = {
|
||||
},
|
||||
|
||||
async getCommitsByUserId( { userId, limit, cursor, publicOnly } ) {
|
||||
limit = limit || 20
|
||||
limit = limit || 25
|
||||
publicOnly = publicOnly !== false
|
||||
|
||||
let query =
|
||||
Commits( )
|
||||
.columns( [ { id: 'commitId' }, 'message', 'referencedObject', 'commits.createdAt', { streamId: 'stream_commits.streamId' }, { streamName: 'streams.name' } ] ).select( )
|
||||
.join( 'stream_commits', 'commits.id', 'stream_commits.commitId' )
|
||||
.join( 'streams', 'stream_commits.streamId', 'streams.id' )
|
||||
.where( 'author', userId )
|
||||
.columns( [ { id: 'commitId' }, 'message', 'referencedObject', 'commits.createdAt', { streamId: 'stream_commits.streamId' }, { streamName: 'streams.name' } ] ).select( )
|
||||
.join( 'stream_commits', 'commits.id', 'stream_commits.commitId' )
|
||||
.join( 'streams', 'stream_commits.streamId', 'streams.id' )
|
||||
.where( 'author', userId )
|
||||
|
||||
if ( publicOnly )
|
||||
query.andWhere( 'streams.isPublic', true )
|
||||
|
||||
@@ -89,8 +89,8 @@ module.exports = {
|
||||
return await Streams( ).where( { id: streamId } ).del( )
|
||||
},
|
||||
|
||||
async getUserStreams( { userId, limit, cursor, publicOnly } ) {
|
||||
limit = limit || 100
|
||||
async getUserStreams( { userId, limit, cursor, publicOnly, searchQuery } ) {
|
||||
limit = limit || 25
|
||||
publicOnly = publicOnly !== false //defaults to true if not provided
|
||||
|
||||
let query = Acl( )
|
||||
@@ -104,14 +104,20 @@ module.exports = {
|
||||
if ( publicOnly )
|
||||
query.andWhere( 'streams.isPublic', true )
|
||||
|
||||
if ( searchQuery )
|
||||
query.andWhere( function () {
|
||||
this.where( 'name', 'ILIKE', `%${ searchQuery }%` )
|
||||
.orWhere( 'description', 'ILIKE', `%${searchQuery}%` )
|
||||
.orWhere( 'id', 'ILIKE', `%${searchQuery}%` ) //potentially useless?
|
||||
} )
|
||||
|
||||
query.orderBy( 'streams.updatedAt', 'desc' ).limit( limit )
|
||||
|
||||
let rows = await query
|
||||
return { streams: rows, cursor: rows.length > 0 ? rows[ rows.length - 1 ].updatedAt.toISOString( ) : null }
|
||||
},
|
||||
|
||||
async getUserStreamsCount( { userId, publicOnly } ) {
|
||||
|
||||
async getUserStreamsCount( {userId, publicOnly, searchQuery } ) {
|
||||
publicOnly = publicOnly !== false //defaults to true if not provided
|
||||
|
||||
let query = Acl( ).count( )
|
||||
@@ -121,6 +127,13 @@ module.exports = {
|
||||
if ( publicOnly )
|
||||
query.andWhere( 'streams.isPublic', true )
|
||||
|
||||
if ( searchQuery )
|
||||
query.andWhere( function () {
|
||||
this.where( 'name', 'ILIKE', `%${searchQuery}%` )
|
||||
.orWhere( 'description', 'ILIKE', `%${searchQuery}%` )
|
||||
.orWhere( 'id', 'ILIKE', `%${searchQuery}%` ) //potentially useless?
|
||||
} )
|
||||
|
||||
let [ res ] = await query
|
||||
return parseInt( res.count )
|
||||
},
|
||||
@@ -128,10 +141,10 @@ module.exports = {
|
||||
async getStreamUsers( { streamId } ) {
|
||||
let query =
|
||||
Acl( ).columns( { role: 'stream_acl.role' }, 'id', 'name' ).select( )
|
||||
.where( { resourceId: streamId } )
|
||||
.rightJoin( 'users', { 'users.id': 'stream_acl.userId' } )
|
||||
.select( 'stream_acl.role', 'username', 'name', 'id' )
|
||||
.orderBy( 'stream_acl.role' )
|
||||
.where( { resourceId: streamId } )
|
||||
.rightJoin( 'users', { 'users.id': 'stream_acl.userId' } )
|
||||
.select( 'stream_acl.role', 'username', 'name', 'id' )
|
||||
.orderBy( 'stream_acl.role' )
|
||||
|
||||
return await query
|
||||
}
|
||||
|
||||
@@ -4,73 +4,73 @@ const crs = require( 'crypto-random-string' )
|
||||
const appRoot = require( 'app-root-path' )
|
||||
const knex = require( `${appRoot}/db/knex` )
|
||||
|
||||
const Users = ( ) => knex( 'users' )
|
||||
const ServerRoles = ( ) => knex( 'server_acl' )
|
||||
const Users = () => knex( 'users' )
|
||||
const Acl = () => knex( 'server_acl' )
|
||||
|
||||
module.exports = {
|
||||
|
||||
/*
|
||||
|
||||
Users
|
||||
Users
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
async createUser( user ) {
|
||||
let [ { count } ] = await ServerRoles( ).where( { role: 'server:admin' } ).count( )
|
||||
let [ {count} ] = await Acl().where( {role: 'server:admin'} ).count()
|
||||
|
||||
user.id = crs( { length: 10 } )
|
||||
user.id = crs( {length: 10} )
|
||||
|
||||
if ( user.password ) {
|
||||
user.passwordDigest = await bcrypt.hash( user.password, 10 )
|
||||
}
|
||||
delete user.password
|
||||
|
||||
let usr = await Users( ).select( 'id' ).where( { email: user.email } ).first( )
|
||||
let usr = await Users().select( 'id' ).where( {email: user.email} ).first()
|
||||
if ( usr ) throw new Error( 'Email taken. Try logging in?' )
|
||||
|
||||
let res = await Users( ).returning( 'id' ).insert( user )
|
||||
let res = await Users().returning( 'id' ).insert( user )
|
||||
|
||||
if ( parseInt( count ) === 0 ) {
|
||||
await ServerRoles( ).insert( { userId: res[ 0 ], role: 'server:admin' } )
|
||||
await Acl().insert( {userId: res[0], role: 'server:admin'} )
|
||||
} else {
|
||||
await ServerRoles( ).insert( { userId: res[ 0 ], role: 'server:user' } )
|
||||
await Acl().insert( {userId: res[0], role: 'server:user'} )
|
||||
}
|
||||
|
||||
return res[ 0 ]
|
||||
return res[0]
|
||||
},
|
||||
|
||||
async findOrCreateUser( { user, rawProfile } ) {
|
||||
let existingUser = await Users( ).select( 'id' ).where( { email: user.email } ).first( )
|
||||
async findOrCreateUser( {user, rawProfile} ) {
|
||||
let existingUser = await Users().select( 'id' ).where( {email: user.email} ).first()
|
||||
|
||||
if ( existingUser )
|
||||
return existingUser
|
||||
|
||||
user.password = crs( { length: 20 } )
|
||||
user.password = crs( {length: 20} )
|
||||
user.verified = true // because we trust the external identity provider, no?
|
||||
return { id: await module.exports.createUser( user ) }
|
||||
return {id: await module.exports.createUser( user )}
|
||||
},
|
||||
|
||||
async getUserById( { userId } ) {
|
||||
let user = await Users( ).where( { id: userId } ).select( '*' ).first( )
|
||||
async getUserById( {userId} ) {
|
||||
let user = await Users().where( {id: userId} ).select( '*' ).first()
|
||||
delete user.passwordDigest
|
||||
return user
|
||||
},
|
||||
|
||||
// TODO: deprecate
|
||||
async getUser( id ) {
|
||||
let user = await Users( ).where( { id: id } ).select( '*' ).first( )
|
||||
let user = await Users().where( {id: id} ).select( '*' ).first()
|
||||
delete user.passwordDigest
|
||||
return user
|
||||
},
|
||||
|
||||
async getUserByEmail( { email } ) {
|
||||
let user = await Users( ).where( { email: email } ).select( '*' ).first( )
|
||||
async getUserByEmail( {email} ) {
|
||||
let user = await Users().where( {email: email} ).select( '*' ).first()
|
||||
delete user.passwordDigest
|
||||
return user
|
||||
},
|
||||
|
||||
async getUserRole( id ) {
|
||||
let { role } = await ServerRoles( ).where( { userId: id } ).select( 'role' ).first( )
|
||||
let {role} = await Acl().where( {userId: id} ).select( 'role' ).first()
|
||||
return role
|
||||
},
|
||||
|
||||
@@ -79,15 +79,35 @@ module.exports = {
|
||||
delete user.passwordDigest
|
||||
delete user.password
|
||||
delete user.email
|
||||
await Users( ).where( { id: id } ).update( user )
|
||||
await Users().where( {id: id} ).update( user )
|
||||
},
|
||||
|
||||
async validatePasssword( { email, password } ) {
|
||||
let { passwordDigest } = await Users( ).where( { email: email } ).select( 'passwordDigest' ).first( )
|
||||
async searchUsers( searchQuery, limit, cursor ) {
|
||||
limit = limit || 25
|
||||
|
||||
let query = Users()
|
||||
.select( 'id', 'username', 'name', 'bio', 'company', 'verified', 'avatar', 'createdAt' )
|
||||
.where( queryBuilder => {
|
||||
queryBuilder.where( {email: searchQuery} ) //match full email or partial username / name
|
||||
queryBuilder.orWhere( 'username', 'ILIKE', `%${searchQuery}%` )
|
||||
queryBuilder.orWhere( 'name', 'ILIKE', `%${searchQuery}%` )
|
||||
} )
|
||||
|
||||
if ( cursor )
|
||||
query.andWhere( 'users.createdAt', '<', cursor )
|
||||
|
||||
query.orderBy( 'users.createdAt', 'desc' ).limit( limit )
|
||||
|
||||
let rows = await query
|
||||
return {users: rows, cursor: rows.length > 0 ? rows[rows.length - 1].createdAt.toISOString() : null}
|
||||
},
|
||||
|
||||
async validatePasssword( {email, password} ) {
|
||||
let {passwordDigest} = await Users().where( {email: email} ).select( 'passwordDigest' ).first()
|
||||
return bcrypt.compare( password, passwordDigest )
|
||||
},
|
||||
|
||||
async deleteUser( id ) {
|
||||
throw new Error( 'not implemented' )
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,13 +65,20 @@ describe( 'Streams', ( ) => {
|
||||
expect( stream.description ).to.equal( 'Wooot' )
|
||||
} )
|
||||
|
||||
it( 'Should get all streams for a user', async ( ) => {
|
||||
it( 'Should get all streams of a user', async ( ) => {
|
||||
let { streams, cursor } = await getUserStreams( { userId: userOne.id } )
|
||||
// console.log( res )
|
||||
expect( streams ).to.have.lengthOf( 2 )
|
||||
expect( cursor ).to.exist
|
||||
} )
|
||||
|
||||
it('Should search all streams of a user', async () => {
|
||||
let {streams, cursor} = await getUserStreams({userId: userOne.id, searchQuery: "woo"})
|
||||
// console.log( res )
|
||||
expect(streams).to.have.lengthOf(1)
|
||||
expect(cursor).to.exist
|
||||
})
|
||||
|
||||
it( 'Should delete a stream', async ( ) => {
|
||||
const id = await createStream( { name: 'mayfly', description: 'wonderful', ownerId: userOne.id } )
|
||||
let all = await getUserStreams( { userId: userOne.id } )
|
||||
|
||||
@@ -11,7 +11,7 @@ chai.use( chaiHttp )
|
||||
|
||||
const knex = require( `${appRoot}/db/knex` )
|
||||
|
||||
const { createUser, getUser, updateUser, deleteUser, validatePasssword } = require( '../services/users' )
|
||||
const {createUser, getUser, searchUsers, updateUser, deleteUser, validatePasssword } = require( '../services/users' )
|
||||
const { createPersonalAccessToken, createAppToken, revokeToken, revokeTokenById, validateToken, getUserTokens } = require( '../services/tokens' )
|
||||
|
||||
describe( 'Actors & Tokens', ( ) => {
|
||||
@@ -61,6 +61,12 @@ describe( 'Actors & Tokens', ( ) => {
|
||||
expect( actor ).to.not.have.property( 'passwordDigest' )
|
||||
} )
|
||||
|
||||
it('Should search and get an users', async () => {
|
||||
let {users} = await searchUsers("gates", 20, null)
|
||||
expect(users).to.have.lengthOf(1)
|
||||
expect(users[0].name).to.equal("Bill Gates")
|
||||
})
|
||||
|
||||
it( 'Should update an actor', async ( ) => {
|
||||
let updatedActor = { ...myTestActor }
|
||||
updatedActor.username = 'didimitrie'
|
||||
|
||||
@@ -28,6 +28,14 @@ When pushing commits to this repo, please follow the following guidelines:
|
||||
|
||||
- Install [commitizen](https://www.npmjs.com/package/commitizen#commitizen-for-contributors) globally (`npm i -g commitizen`).
|
||||
- When ready to commit, type in the commandline `git cz` & follow the prompts.
|
||||
- Install eslint globally `npm i -g eslint`
|
||||
- if using VS code install the `eslint` extension
|
||||
- we also recommend setting it to run on save by adding the following VS Code setting
|
||||
```
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
|
||||
Reference in New Issue
Block a user