This commit is contained in:
2026-05-13 19:58:16 +03:00
commit f5adeb292b
78 changed files with 12024 additions and 0 deletions

24
lib/factory/channel.js Normal file
View File

@@ -0,0 +1,24 @@
const Joi = require('joi')
const validate = require('./validate')
//
// Define the schema
//
const schema = {
team: Joi.string(),
name: Joi.string().regex(/^[a-z0-9_-]+$/),
display_name: Joi.string(),
header: Joi.string().allow('').optional(),
purpose: Joi.string().allow('').optional(),
type: Joi.string().valid('O', 'P')
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'channel',
channel: validate(schema, props)
}
}

View File

@@ -0,0 +1,20 @@
const Joi = require('joi')
const validate = require('./validate')
//
// Define the schema
//
const schema = {
header: Joi.string().allow('').optional(),
members: Joi.array().items(Joi.string()).min(2).max(8)
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'direct_channel',
direct_channel: validate(schema, props)
}
}

21
lib/factory/directPost.js Normal file
View File

@@ -0,0 +1,21 @@
const Joi = require('joi')
const validate = require('./validate')
const postPartial = require('./postPartial')
//
// Define the schema
//
const schema = {
channel_members: Joi.array().items(Joi.string()).min(2),
...postPartial,
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'direct_post',
direct_post: validate(schema, props)
}
}

20
lib/factory/emoji.js Normal file
View File

@@ -0,0 +1,20 @@
const Joi = require('joi')
const validate = require('./validate')
//
// Define the schema
//
const schema = {
name: Joi.string(),
image: Joi.string(),
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'emoji',
emoji: validate(schema, props)
}
}

19
lib/factory/index.js Normal file
View File

@@ -0,0 +1,19 @@
const version = require('./version')
const emoji = require('./emoji')
const team = require('./team')
const channel = require('./channel')
const user = require('./user')
const post = require('./post')
const directChannel = require('./directChannel')
const directPost = require('./directPost')
module.exports = {
version,
emoji,
team,
channel,
user,
post,
directChannel,
directPost
}

22
lib/factory/post.js Normal file
View File

@@ -0,0 +1,22 @@
const Joi = require('joi')
const validate = require('./validate')
const postPartial = require('./postPartial')
//
// Define the schema
//
const schema = {
team: Joi.string(),
channel: Joi.string(),
...postPartial,
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'post',
post: validate(schema, props)
}
}

View File

@@ -0,0 +1,31 @@
const Joi = require('joi')
const attachment = Joi.object({
path: Joi.string()
})
const reaction = Joi.object({
user: Joi.string(),
emoji_name: Joi.string(),
create_at: Joi.number(),
})
const messagePartial = {
user: Joi.string(),
message: Joi.string().allow(''),
attachments: Joi.array().items(attachment).optional(),
flagged_by: Joi.array().items(Joi.string()).optional(),
reactions: Joi.array().items(reaction).optional(),
create_at: Joi.number(),
}
const reply = Joi.object().keys(messagePartial)
//
// Define the schema
//
module.exports = {
...messagePartial,
replies: Joi.array().items(reply).optional(),
}

23
lib/factory/team.js Normal file
View File

@@ -0,0 +1,23 @@
const Joi = require('joi')
const validate = require('./validate')
//
// Define the schema
//
const schema = {
name: Joi.string(),
display_name: Joi.string(),
description: Joi.string(),
type: Joi.string().valid('O', 'I'),
allow_open_invite: Joi.boolean()
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'team',
team: validate(schema, props)
}
}

View File

@@ -0,0 +1,35 @@
const expect = require('chai').expect
const channel = require('../channel')
const basic = {
team: 'test-team',
name: 'test-channel',
display_name: 'Test Channel',
header: 'Test Channel Header',
purpose: 'Test the channel generator',
type: 'P'
}
describe('team factory', function() {
it('should produce a valid object', function() {
var c = channel(basic)
expect(c).to.be.an('object')
expect(c).to.deep.equal({
type: 'channel',
channel: basic
})
})
it('should prevent an invalid type', function() {
try {
channel(Object.assign({}, basic, {
type: 'X'
}))
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"type" must be one of [O, P]')
}
})
})

View File

@@ -0,0 +1,35 @@
const expect = require('chai').expect
const directChannel = require('../directChannel')
const basic = {
members: [
'username1',
'username2'
]
}
describe('team factory', function() {
it('should produce a valid object', function() {
var c = directChannel(basic)
expect(c).to.be.an('object')
expect(c).to.deep.equal({
type: 'direct_channel',
direct_channel: basic
})
})
it('should prevent less than 2 members', function() {
try {
directChannel(Object.assign({}, basic, {
members:[
'username1'
]
}))
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"members" must contain at least 2 items')
}
})
})

View File

@@ -0,0 +1,53 @@
const expect = require('chai').expect
const directPost = require('../directPost')
const basic = {
channel_members: [
'username1',
'username2'
],
user: 'username1',
message: 'carpe diem',
create_at: new Date().getTime()
}
describe('post factory', function() {
it('should produce a valid object', function() {
var p = directPost(basic)
expect(p).to.be.an('object')
expect(p).to.deep.equal({
type: 'direct_post',
direct_post: basic
})
})
it('should ensure message is not empty', function() {
try {
var p = directPost(Object.assign({}, basic, {
message: ''
}))
expect(p).to.be.undefined
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"message" is not allowed to be empty')
}
})
it('should prevent less than 2 members', function() {
try {
var p = directPost(Object.assign({}, basic, {
channel_members:[
'username1'
]
}))
expect(p).to.be.undefined
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"channel_members" must contain at least 2 items')
}
})
})

35
lib/factory/test/post.js Normal file
View File

@@ -0,0 +1,35 @@
const expect = require('chai').expect
const post = require('../post')
const basic = {
team: 'test',
channel: 'channel',
user: 'user',
message: 'carpe diem',
create_at: new Date().getTime()
}
describe('post factory', function() {
it('should produce a valid object', function() {
var p = post(basic)
expect(p).to.be.an('object')
expect(p).to.deep.equal({
type: 'post',
post: basic
})
})
it('should ensure message is not empty', function() {
try {
var p = post(Object.assign({}, basic, {
message: ''
}))
expect(p).to.be.undefined
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"message" is not allowed to be empty')
}
})
})

34
lib/factory/test/team.js Normal file
View File

@@ -0,0 +1,34 @@
const expect = require('chai').expect
const team = require('../team')
const basic = {
name: 'test-team',
display_name: 'Test Team',
description: 'A test team for testing',
type: 'O',
allow_open_invite: true
}
describe('team factory', function() {
it('should produce a valid object', function() {
var t = team(basic)
expect(t).to.be.an('object')
expect(t).to.deep.equal({
type: 'team',
team: basic
})
})
it('should prevent an invalid type', function() {
try {
team(Object.assign({}, basic, {
type: 'X'
}))
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"type" must be one of [O, I]')
}
})
})

42
lib/factory/test/user.js Normal file
View File

@@ -0,0 +1,42 @@
const expect = require('chai').expect
const user = require('../user')
const basic = {
username: 'user.name',
email: 'user@example.gov',
auth_service: 'ldap',
auth_data: 'username-field-reference',
teams: [{
name: 'test',
channels: [{
name: 'channel-1'
}, {
name: 'channel-2'
}]
}]
}
describe('user factory', function() {
it('should produce a valid object', function() {
var u = user(basic)
expect(u).to.be.an('object')
expect(u).to.deep.equal({
type: 'user',
user: basic
})
})
it('should ensure email is valid', function() {
try {
var u = user(Object.assign({}, basic, {
email: 'foo@bar'
}))
expect(u).to.be.undefined
}
catch (e) {
expect(e).to.be.an('error')
expect(e.details[0].message).to.equal('"email" must be a valid email')
}
})
})

View File

@@ -0,0 +1,13 @@
const expect = require('chai').expect
const version = require('../version')
describe('version factory', function() {
it('should produce a valid version', function() {
var v = version()
expect(v).to.be.an('object')
expect(v).to.deep.equal({
type: 'version',
version: 1
})
})
})

72
lib/factory/user.js Normal file
View File

@@ -0,0 +1,72 @@
const Joi = require('joi')
const validate = require('./validate')
const validateRoles = function (value, helper, allowed) {
const roles = value.split(' ')
if (value.length < 8) {
return helper.message('Password must be at least 8 characters long')
} else {
return true
}
}
//
// Define the schema
//
const schema = {
profile_image: Joi.string().optional(),
username: Joi.string(),
email: Joi.string().email({
errorLevel: true,
minDomainAtoms: 2
}),
auth_service: Joi.string().valid(
'',
'gitlab',
'ldap',
'saml',
'google',
'office365'
).optional(),
auth_data: Joi.string().optional().allow(''),
password: Joi.string().optional(),
nickname: Joi.string().optional(),
first_name: Joi.string().optional(),
last_name: Joi.string().optional(),
position: Joi.string().optional(),
roles: Joi.string().optional().valid(
'system_user',
'system_admin system_user'
),
teams: Joi.array().items(
Joi.object({
name: Joi.string(),
roles: Joi.string().optional().valid(
'team_user',
'team_admin team_user'
),
channels: Joi.array().items(
Joi.object({
name: Joi.string(),
roles: Joi.string().optional().valid(
'channel_user',
'channel_user channel_admin'
)
})
)
})
),
notify_props: Joi.object({
mention_keys: Joi.string().optional().allow(''),
}).optional(),
}
//
// Generate a valid object
//
module.exports = function (props) {
return {
type: 'user',
user: validate(schema, props)
}
}

21
lib/factory/validate.js Normal file
View File

@@ -0,0 +1,21 @@
const Joi = require('joi')
module.exports = function (schema, props) {
//
// Validate and remove unknown keys
//
var {error, value} = Joi.validate(props, schema, {
presence: 'required',
stripUnknown: true
})
//
// Throw validation errors
//
if (error) {
throw error
}
//
// Return the value
//
return value
}

11
lib/factory/version.js Normal file
View File

@@ -0,0 +1,11 @@
//
// Generate a version object. This
// is the only valid value as of
// now
//
module.exports = function() {
return {
type: 'version',
version: 1
}
}