22
33const fs = require ( 'fs' )
44const path = require ( 'path' )
5+ const assert = require ( 'assert' )
56
67function TicketError ( message ) {
78 this . name = 'TicketError' ;
@@ -25,80 +26,83 @@ const Sample = {
2526
2627const actions = [
2728{
28- action : ( _tickets , _message ) => 'DEFAULT ACTION' ,
29+ action : ( _data , _message ) => 'DEFAULT ACTION' ,
2930 regexp : / ^ $ / i,
3031 reply : ( message , _output ) => `Yes ${ message . userName } ?` ,
3132} ,
3233{
33- action : ( _tickets , _message ) => help ( ) ,
34+ action : ( _data , _message ) => help ( ) ,
3435 regexp : / h e l p / i,
3536 reply : ( message , output ) => `\n${ output } ` ,
3637} ,
3738{
38- action : ( tickets , _message , id ) => closeTicket ( tickets , id ) ,
39+ action : ( data , _message , id ) => closeTicket ( data . tickets , id ) ,
3940 regexp : / c l o s e # ? ( [ 0 - 9 ] * ) / i,
4041 reply : ( message , output ) => `ticket #${ output . id } is closed` ,
4142} ,
4243{
43- action : ( tickets , message , content ) =>
44- openTicket ( tickets , message , content ) ,
44+ action : ( data , message , content ) =>
45+ openTicket ( data . tickets , message , content ) ,
4546 regexp : / p l e a s e ( .* ) / i,
4647 reply : ( message , output ) => `will ${ output . content } (ticket #${ output . id } )` ,
4748} ,
4849{
49- action : ( tickets , _message , id ) => findTicket ( tickets , id ) ,
50+ action : ( data , _message , id ) => findTicket ( data . tickets , id ) ,
5051 regexp : / s h o w # ? ( [ 0 - 9 ] * ) / i,
5152 reply : ( message , output ) => showTicket ( output ) ,
5253} ,
5354{
5455 /* eslint-disable max-params */
55- action : ( tickets , _m , id , comment ) => [ findTicket ( tickets , id ) , comment ] ,
56+ action : ( data , _m , id , comment ) => [ findTicket ( data . tickets , id ) , comment ] ,
5657 regexp : / t i c k e t # ? ( [ 0 - 9 ] * ) ( .* ) $ / i,
5758 reply : ( message , output ) => addComment ( output [ 0 ] , output [ 1 ] ) ,
5859} ,
5960{
60- action : ( tickets , message , id ) => assign ( tickets , id , message . userName ) ,
61+ action : ( data , message , id ) => assign ( data . tickets , id , message . userName ) ,
6162 regexp : / t a k e # ? ( [ 0 - 9 ] * ) / i,
6263 reply : ( message , output ) => `ticket #${ output . id } is assigned to ${ output . assignee } ` ,
6364} ,
6465{
6566 /* eslint-disable max-params */
66- action : ( tickets , _message , id , assignee ) => assign ( tickets , id , assignee ) ,
67+ action : ( data , _message , id , assignee ) =>
68+ assign ( data . tickets , id , assignee ) ,
6769 regexp : / a s s i g n # ? ( [ 0 - 9 ] * ) t o ( \w * ) / i,
6870 reply : ( message , output ) => `ticket #${ output . id } is assigned to ${ output . assignee } ` ,
6971} ,
7072{
71- action : ( tickets , _message ) => tickets ,
73+ action : ( data , _message ) => data . tickets ,
7274 regexp : / d e b u g / i,
7375 reply : ( message , output ) => JSON . stringify ( output , null , 4 ) ,
7476} ,
7577{
76- action : ( tickets , _message , username ) => [ tickets , username . toLowerCase ( ) ] ,
78+ action : ( data , _message , username ) => [
79+ data . tickets , username . toLowerCase ( )
80+ ] ,
7781 regexp : / t o d o ? ( \w * ) / i,
7882 reply : ( message , output ) => showTickets ( output [ 0 ] , [ 'open' ] , output [ 1 ] ) ,
7983} ,
8084{
81- action : ( tickets , _message ) => tickets ,
85+ action : ( data , _message ) => data . tickets ,
8286 regexp : / m i n e / i,
8387 reply : ( message , output ) => showTickets ( output , [ 'open' ] , message . userName ) ,
8488} ,
8589{
86- action : ( tickets , _message ) => tickets ,
90+ action : ( data , _message ) => data . tickets ,
8791 regexp : / h i s t o r y / i,
8892 reply : ( message , output ) => showTickets ( output , [ 'open' , 'closed' ] ) ,
8993} ,
9094{
91- action : ( tickets , _message ) => forget ( tickets ) ,
95+ action : ( data , _message ) => forget ( data . tickets ) ,
9296 regexp : / f o r g e t i t / i,
9397 reply : ( message , output ) => `deleted ${ output } tickets` ,
9498} ,
9599{
96- action : ( tickets , _message , type ) => gimme ( type ) ,
100+ action : ( data , _message , type ) => gimme ( data . fs , type ) ,
97101 regexp : / g i m m e \s * a * n * \s * ( \w * ) / i,
98102 reply : ( message , output ) => `${ message . userName } ${ output [ 0 ] . toLowerCase ( ) } ${ output . substr ( 1 ) } ` ,
99103} ,
100104{
101- action : ( tickets , _message , type ) => listType ( type ) ,
105+ action : ( data , _message , type ) => listType ( data . fs , type ) ,
102106 regexp : / w h a t \s * ( \w * ) ( y o u ) ? ( g o t ) ? \? ? / i,
103107 reply : ( message , output ) => `${ output . join ( '\n' ) } ` ,
104108} ,
@@ -204,11 +208,6 @@ function help() {
204208 return actions . map ( ( action ) => `${ action . regexp . toString ( ) } ` ) . join ( '\n' )
205209}
206210
207- function getRandomInt ( min , max ) {
208- const range = max - min + 1 + min
209- return Math . floor ( Math . random ( ) * range ) ;
210- }
211-
212211function addComment ( ticket , comment ) {
213212 if ( ! ( ticket . comments instanceof Array ) ) {
214213 ticket . comments = [ ]
@@ -218,20 +217,22 @@ function addComment(ticket, comment) {
218217}
219218var sources = { }
220219
221- function gimme ( type ) {
222- const saying = listType ( type ) [ getRandomInt ( 0 , sources [ type ] . length ) ]
223- return saying
220+ function gimme ( injectedFs , type ) {
221+ const typeList = listType ( injectedFs , type )
222+ const randomIndex = Math . floor ( Math . random ( ) * sources [ type ] . length )
223+ const result = typeList [ randomIndex ]
224+ return result
224225}
225226
226- function listType ( type ) {
227+ function listType ( injectedFs , type ) {
227228 const typePath = path . basename ( `${ type } .txt` )
228229 /* eslint-disable no-sync */
229- if ( ! fs . existsSync ( typePath ) ) {
230+ if ( ! injectedFs . existsSync ( typePath ) ) {
230231 throw new TicketError ( `I don't know how to give you ${ type } !` )
231232 }
232233 if ( ! sources [ type ] ) {
233234 /* eslint-disable no-sync */
234- const content = fs . readFileSync ( typePath )
235+ const content = injectedFs . readFileSync ( typePath )
235236 sources [ type ] = content . toString ( ) . split ( '\n' )
236237 }
237238 return sources [ type ]
@@ -254,7 +255,9 @@ function searchRegexp(action) {
254255 return false
255256}
256257
257- function process ( tickets , message ) {
258+ function process ( data , message ) {
259+ assert ( isValidTickets ( data . tickets ) ,
260+ `Expecting valid tickets data key, got: ${ JSON . stringify ( data . tickets ) } ` )
258261 const findParams = {
259262 content : message . content ,
260263 result : null
@@ -264,7 +267,7 @@ function process(tickets, message) {
264267 var reply ;
265268 if ( action ) {
266269 try {
267- var output = action . action ( tickets , message , ...findParams . result )
270+ var output = action . action ( data , message , ...findParams . result )
268271 reply = `${ action . reply . bind ( output ) ( message , output ) } `
269272 } catch ( e ) {
270273 if ( e instanceof TicketError ) {
@@ -284,7 +287,23 @@ function createTickets() {
284287 }
285288}
286289
290+ function isValidTickets ( tickets ) {
291+ if ( ! tickets ) {
292+ return false
293+ }
294+ if ( ! ( tickets instanceof Object ) ) {
295+ return false
296+ }
297+ if ( ! Number . isInteger ( tickets . lastId ) ) {
298+ return false
299+ }
300+ return true
301+ }
302+
287303function store ( storePath , tickets ) {
304+ if ( ! isValidTickets ( tickets ) ) {
305+ throw new TicketError ( `refusing to write invalid data: ${ JSON . stringify ( tickets ) } ` )
306+ }
288307 /* eslint-disable no-sync */
289308 fs . writeFileSync ( storePath , JSON . stringify ( tickets , null , 4 ) )
290309}
@@ -295,7 +314,11 @@ function load(storePath) {
295314 /* eslint-disable no-sync */
296315 const datastore = fs . readFileSync ( storePath ) . toString ( )
297316 try {
298- return JSON . parse ( datastore )
317+ const tickets = JSON . parse ( datastore )
318+ if ( ! isValidTickets ( tickets ) ) {
319+ throw new TicketError ( `does not contain valid data: ${ storePath } ` )
320+ }
321+ return tickets
299322 } catch ( e ) {
300323 if ( e instanceof SyntaxError ) {
301324 throw new TicketError ( `invalid content of file: ${ storePath } ` )
@@ -310,6 +333,7 @@ function load(storePath) {
310333module . exports = {
311334 TicketError,
312335 createTickets,
336+ isValidTickets,
313337 load,
314338 openTicket,
315339 process,
0 commit comments