@@ -15,59 +15,51 @@ var database;
15
15
// exit on failure
16
16
function prepareDatabase ( )
17
17
{
18
- // load the database from file
19
- database = new sqlite3 . Database ( config . dbFilename , sqlite3 . OPEN_READONLY , e => {
20
- if ( e ) exit ( `Error opening database: ${ e } ` ) ;
21
- } ) ;
18
+ // load the database from file
19
+ database = new sqlite3 . Database ( config . dbFilename , sqlite3 . OPEN_READONLY , e => {
20
+ if ( e ) exit ( `Error opening database: ${ e } ` ) ;
21
+ } ) ;
22
22
} ;
23
23
24
24
// close the database if its open
25
25
function closeDatabase ( )
26
26
{
27
- if ( database ) database . close ( ) . catch ( console . error ) ;
28
- }
29
-
30
- // get a row in a table
31
- function selectRow ( table , whereColumn , equals , callback )
32
- {
33
- // is this safe?
34
- const sql = `SELECT * FROM ${ table } WHERE ${ whereColumn } = "${ equals } "` ;
35
- database . all ( sql , [ ] , ( e , rows ) => {
36
- if ( e ) exit ( `Error querying database: ${ e } ` ) ;
37
- else callback ( rows ) ;
38
- } ) ;
27
+ if ( database ) database . close ( ) . catch ( console . error ) ;
39
28
}
40
29
41
30
// take a timestamp and format it
42
31
function formatDate ( timestamp )
43
32
{
44
- return new Date ( timestamp ) . toUTCString ( ) ;
33
+ return new Date ( timestamp ) . toUTCString ( ) ;
45
34
}
46
35
47
36
// format a massege for code blocks
48
37
function formatMessage ( string )
49
38
{
50
- const regex = / \` \` \` ( ( [ a - z ] + ) \n ) ? \n * ( [ \s \S ] * ?) \n * \` \` \` / g;
51
- return string . replace ( regex , ( match , p1 , p2 , p3 , offset , string ) =>
52
- `<div class="code">${ p2 ? `<span class="lang">#${ p2 } </span><br />` : "" } ${ p3 } </div>` ) ;
39
+ const regex = / \` \` \` ( ( [ a - z ] + ) \n ) ? \n * ( [ \s \S ] * ?) \n * \` \` \` / g;
40
+ const s = string . replace ( regex , ( match , p1 , p2 , p3 , offset , string ) =>
41
+ `<div class="code">${ p2 ? `<span class="lang">#${ p2 } </span><br />` : "" } ${ p3 . replace ( / \n / g, "<br />" ) } </div>` ) ;
42
+ // also parse inline `code` and urls
43
+ return s ;
53
44
}
54
45
55
46
// make html output for a message
56
- function makeMessagePage ( message , revisions )
47
+ function makeMessagePage ( rows )
57
48
{
58
- // just something for now, i don't know what we actually want to do
59
- const header = `
60
- <span class="field">Message ID:</span> <span class="value">${ message . msgId } </span><br />
61
- <span class="field">Author:</span> <span class="value">${ message . author } </span><br />
62
- <span class="field">Channel:</span> <span class="value">${ message . channel } </span><br />
63
- ` ;
64
- const body = revisions . map ( revision => `
49
+ const body = rows . map ( row => `
50
+ <a class="perma" href="/code?msgId=${ row . msgId } ">permalink</a><br />
51
+ Author: ${ row . author } <br />
52
+ Channel: ${ row . channel } <br />` + row . revisions . map ( revision => `
65
53
<span class="timestamp">${ formatDate ( revision . date ) } </span>
66
54
<div class="messageBody">${ formatMessage ( revision . fullMessage ) } </div>
67
- ` ) . join ( "<br /><br />" ) ;
55
+ ` ) . join ( "<br /><br />" ) ) . join ( "<br /><br />" ) ;
68
56
69
- return `
57
+ return `
70
58
<style>
59
+ .perma
60
+ {
61
+ font-size: small;
62
+ }
71
63
.wrapper
72
64
{
73
65
width: 400px;
@@ -108,60 +100,122 @@ function makeMessagePage(message, revisions)
108
100
</style>
109
101
110
102
<div class="wrapper">
111
- ${ header }
112
- <br />
113
103
${ body }
114
104
</div>
115
105
` ;
116
106
}
117
107
118
- // request a message by id
119
- frontend . get ( "/code/:id" , ( request , response ) => {
120
- // select the message by id
121
- selectRow ( "Message" , "msgId" , request . params . id , rows => {
122
- if ( rows . length )
108
+ // search page
109
+ frontend . get ( "/" , ( request , response ) => {
110
+ const sql = `SELECT DISTINCT author FROM Message` ;
111
+ database . all ( sql , [ ] , ( e , authors ) => {
112
+ if ( e ) exit ( `Error querying database: ${ e } ` ) ;
113
+ else
114
+ {
115
+ const sql = `SELECT DISTINCT channel FROM Message` ;
116
+ database . all ( sql , [ ] , ( e , channels ) => {
117
+ if ( e ) exit ( `Error querying database: ${ e } ` ) ;
118
+ else
123
119
{
124
- // assuming there's only one message per id
125
- // as there should be
126
- const message = rows [ 0 ] ;
127
-
128
- // select all the revisions of this message
129
- selectRow ( "Content" , "associatedMsg" , message . msgId , rows => {
130
- if ( rows . length )
131
- {
132
- // should we sort in sqlite instead of here?
133
- // sort the revisions by timestamp
134
- const sorted = rows . sort ( ( a , b ) => a . date - b . date ) ;
135
-
136
- // what should we actually be displaying here?
137
- // a pretty display for the user?
138
- // or some raw information?
139
- // also, should we just show the most recent revision?
140
- response . send ( makeMessagePage ( message , rows ) ) ;
141
- }
142
- else response . send ( "No revisions found!" ) ;
143
- } ) ;
120
+ response . send ( `
121
+ <form action="/code/">
122
+ <label for="author">Author</label>
123
+ <select id="author" name="author">
124
+ <option value="">*</option>
125
+ ${ authors . map ( author => `<option value="${ author . author } ">${ author . author } </option>` ) . join ( "" ) }
126
+ </select><br />
127
+ <label for="channel">Channel</label>
128
+ <select id="channel" name="channel">
129
+ <option value="">*</option>
130
+ ${ channels . map ( channel => `<option value="${ channel . channel } ">${ channel . channel } </option>` ) . join ( "" ) }
131
+ </select><br />
132
+ <label for="from">From</label>
133
+ <input id="from" name="from" type="date"><br />
134
+ <label for="to">To</label>
135
+ <input id="to" name="to" type="date"><br />
136
+ <input type="submit">
137
+ </form>
138
+ ` ) ;
144
139
}
145
- else response . send ( "Message not found!" ) ;
146
- } ) ;
140
+ } ) ;
141
+ }
142
+ } ) ;
143
+ } ) ;
144
+
145
+ function strtotime ( string )
146
+ {
147
+ return new Date ( string ) . getTime ( ) ;
148
+ }
149
+
150
+ // filter messages query
151
+ frontend . get ( "/code/" , ( request , response ) => {
152
+ var sql = `SELECT * FROM Message` ;
153
+ const bindings = [ ] ;
154
+
155
+ var kw = "WHERE" ;
156
+ if ( request . query . author )
157
+ {
158
+ sql += ` ${ kw } author = ?` ;
159
+ bindings . push ( request . query . author ) ;
160
+ kw = "AND" ;
161
+ }
162
+ if ( request . query . channel )
163
+ {
164
+ sql += ` ${ kw } channel = ?` ;
165
+ bindings . push ( request . query . channel ) ;
166
+ kw = "AND" ;
167
+ }
168
+ if ( request . query . msgId )
169
+ {
170
+ sql += ` ${ kw } msgId = ?` ;
171
+ bindings . push ( request . query . msgId ) ;
172
+ kw = "AND" ;
173
+ }
174
+
175
+ database . all ( sql , bindings , ( e , messageRows ) => {
176
+ if ( e ) exit ( `Error querying database: ${ e } ` ) ;
177
+ else
178
+ {
179
+ const sql = `SELECT * FROM Content` ;
180
+ database . all ( sql , [ ] , ( e , contentRows ) => {
181
+ if ( e ) exit ( `Error querying database: ${ e } ` ) ;
182
+ else
183
+ {
184
+ var rows = messageRows ;
185
+ rows = rows . map ( row => {
186
+ row . revisions = contentRows
187
+ . filter ( revision => revision . associatedMsg === row . msgId ) ;
188
+ delete row . revisions . associatedMsg ;
189
+ return row ;
190
+ } ) ;
191
+ if ( request . query . from )
192
+ rows = rows . filter ( row => row . revisions [ 0 ] . date >= strtotime ( request . query . from ) ) ;
193
+ if ( request . query . to )
194
+ rows = rows . filter ( row => row . revisions [ 0 ] . date < strtotime ( request . query . to ) ) ;
195
+ if ( request . query . as === "json" ) response . send ( rows ) ;
196
+ else response . send ( makeMessagePage ( rows ) ) ;
197
+ } ;
198
+ } ) ;
199
+ } ;
200
+ } ) ;
147
201
} ) ;
148
202
149
203
// exit with error message
150
204
function exit ( message )
151
205
{
152
- console . error ( message ) ;
153
- closeDatabase ( ) ;
154
- process . exit ( 1 ) ;
206
+ console . error ( message ) ;
207
+ closeDatabase ( ) ;
208
+ process . exit ( 1 ) ;
155
209
}
156
210
157
211
// start the server!
158
212
function main ( )
159
213
{
160
- // open the database
161
- prepareDatabase ( ) ;
214
+ // open the database
215
+ prepareDatabase ( ) ;
162
216
163
- // start the server listening
164
- frontend . listen ( config . port , ( ) => console . log ( `Server running on port ${ config . port } !` ) ) ;
217
+ // start the server listening
218
+ frontend . listen ( config . port , ( ) => console . log ( `Server running on port ${ config . port } !` ) ) ;
165
219
}
166
220
167
221
// go!
0 commit comments