Fossil SCM
Add the /chat-delete page that can be used to by an XHR to delete a particular chat message.
Commit
2480ce94653f2b9a0faa998b1c25975b2adb792c0dd5827cc8f38ae7393fe443
Parent
63ec4a5bcd5765b…
1 file changed
+62
-11
+62
-11
| --- src/chat.c | ||
| +++ src/chat.c | ||
| @@ -152,16 +152,17 @@ | ||
| 152 | 152 | /* Definition of repository tables used by chat |
| 153 | 153 | */ |
| 154 | 154 | static const char zChatSchema1[] = |
| 155 | 155 | @ CREATE TABLE repository.chat( |
| 156 | 156 | @ msgid INTEGER PRIMARY KEY AUTOINCREMENT, |
| 157 | -@ mtime JULIANDAY, | |
| 158 | -@ xfrom TEXT, | |
| 159 | -@ xmsg TEXT, | |
| 160 | -@ file BLOB, | |
| 161 | -@ fname TEXT, | |
| 162 | -@ fmime TEXT | |
| 157 | +@ mtime JULIANDAY, -- Time for this entry - Julianday Zulu | |
| 158 | +@ xfrom TEXT, -- Login of the sender | |
| 159 | +@ xmsg TEXT, -- Raw, unformatted text of the message | |
| 160 | +@ file BLOB, -- Text of the uploaded file, or NULL | |
| 161 | +@ fname TEXT, -- Filename of the uploaded file, or NULL | |
| 162 | +@ fmime TEXT, -- MIMEType of the upload file, or NULL | |
| 163 | +@ mdel INT -- msgid of another message to delete | |
| 163 | 164 | @ ); |
| 164 | 165 | ; |
| 165 | 166 | |
| 166 | 167 | |
| 167 | 168 | /* |
| @@ -169,10 +170,12 @@ | ||
| 169 | 170 | ** if they do not. |
| 170 | 171 | */ |
| 171 | 172 | static void chat_create_tables(void){ |
| 172 | 173 | if( !db_table_exists("repository","chat") ){ |
| 173 | 174 | db_multi_exec(zChatSchema1/*works-like:""*/); |
| 175 | + }else if( !db_table_has_column("repository","chat","mdel") ){ | |
| 176 | + db_multi_exec("ALTER TABLE chat ADD COLUMN mdel INT"); | |
| 174 | 177 | } |
| 175 | 178 | } |
| 176 | 179 | |
| 177 | 180 | /* |
| 178 | 181 | ** WEBPAGE: chat-send |
| @@ -235,18 +238,21 @@ | ||
| 235 | 238 | ** | "uclr": text // Color string associated with the user |
| 236 | 239 | ** | "xmsg": text // HTML text of the message |
| 237 | 240 | ** | "fsize": integer // file attachment size in bytes |
| 238 | 241 | ** | "fname": text // Name of file attachment |
| 239 | 242 | ** | "fmime": text // MIME-type of file attachment |
| 243 | +** | "mdel": integer // message id of prior message to delete | |
| 240 | 244 | ** | } |
| 241 | 245 | ** | ] |
| 242 | 246 | ** | } |
| 243 | 247 | ** |
| 244 | 248 | ** The "fname" and "fmime" fields are only present if "fsize" is greater |
| 245 | 249 | ** than zero. The "xmsg" field may be an empty string if "fsize" is zero. |
| 246 | 250 | ** |
| 247 | 251 | ** The "msgid" values will be in increasing order. |
| 252 | +** | |
| 253 | +** The "mdel" will only exist if "xmsg" is an empty string and "fsize" is zero. | |
| 248 | 254 | */ |
| 249 | 255 | void chat_poll_webpage(void){ |
| 250 | 256 | Blob json; /* The json to be constructed and returned */ |
| 251 | 257 | sqlite3_int64 dataVersion; /* Data version. Used for polling. */ |
| 252 | 258 | sqlite3_int64 newDataVers; |
| @@ -258,11 +264,12 @@ | ||
| 258 | 264 | if( !g.perm.Chat ) return; |
| 259 | 265 | chat_create_tables(); |
| 260 | 266 | cgi_set_content_type("text/json"); |
| 261 | 267 | dataVersion = db_int64(0, "PRAGMA data_version"); |
| 262 | 268 | db_prepare(&q1, |
| 263 | - "SELECT msgid, datetime(mtime), xfrom, xmsg, length(file), fname, fmime" | |
| 269 | + "SELECT msgid, datetime(mtime), xfrom, xmsg, length(file)," | |
| 270 | + " fname, fmime, mdel" | |
| 264 | 271 | " FROM chat" |
| 265 | 272 | " WHERE msgid>%d" |
| 266 | 273 | " ORDER BY msgid", |
| 267 | 274 | msgid |
| 268 | 275 | ); |
| @@ -272,13 +279,14 @@ | ||
| 272 | 279 | while( db_step(&q1)==SQLITE_ROW ){ |
| 273 | 280 | int id = db_column_int(&q1, 0); |
| 274 | 281 | const char *zDate = db_column_text(&q1, 1); |
| 275 | 282 | const char *zFrom = db_column_text(&q1, 2); |
| 276 | 283 | const char *zRawMsg = db_column_text(&q1, 3); |
| 277 | - const int nByte = db_column_int(&q1, 4); | |
| 284 | + int nByte = db_column_int(&q1, 4); | |
| 278 | 285 | const char *zFName = db_column_text(&q1, 5); |
| 279 | 286 | const char *zFMime = db_column_text(&q1, 6); |
| 287 | + int iToDel = db_column_int(&q1, 7); | |
| 280 | 288 | char *zMsg; |
| 281 | 289 | cnt++; |
| 282 | 290 | blob_append(&json, zSep, -1); |
| 283 | 291 | zSep = ",\n"; |
| 284 | 292 | blob_appendf(&json, "{\"msgid\":%d,\"mtime\":%!j,", id, zDate); |
| @@ -286,20 +294,25 @@ | ||
| 286 | 294 | blob_appendf(&json, "\"uclr\":%!j,", hash_color(zFrom)); |
| 287 | 295 | |
| 288 | 296 | /* TBD: Convert the raw message into HTML, perhaps by running it |
| 289 | 297 | ** through a text formatter, or putting markup on @name phrases, |
| 290 | 298 | ** etc. */ |
| 291 | - zMsg = mprintf("%h", zRawMsg); | |
| 299 | + zMsg = mprintf("%h", zRawMsg ? zRawMsg : ""); | |
| 292 | 300 | blob_appendf(&json, "\"xmsg\":%!j,", zMsg); |
| 293 | 301 | fossil_free(zMsg); |
| 294 | 302 | |
| 295 | 303 | if( nByte==0 ){ |
| 296 | - blob_appendf(&json, "\"fsize\":0}"); | |
| 304 | + blob_appendf(&json, "\"fsize\":0"); | |
| 297 | 305 | }else{ |
| 298 | - blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j}", | |
| 306 | + blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j", | |
| 299 | 307 | nByte, zFName, zFMime); |
| 300 | 308 | } |
| 309 | + if( iToDel ){ | |
| 310 | + blob_appendf(&json, ",\"mdel\":%d}", iToDel); | |
| 311 | + }else{ | |
| 312 | + blob_append(&json, "}", 1); | |
| 313 | + } | |
| 301 | 314 | } |
| 302 | 315 | if( cnt ){ |
| 303 | 316 | blob_append(&json, "\n]}", 3); |
| 304 | 317 | cgi_set_content(&json); |
| 305 | 318 | break; |
| @@ -341,5 +354,43 @@ | ||
| 341 | 354 | if( zMime==0 ) return; |
| 342 | 355 | db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid); |
| 343 | 356 | cgi_set_content_type(zMime); |
| 344 | 357 | cgi_set_content(&r); |
| 345 | 358 | } |
| 359 | + | |
| 360 | + | |
| 361 | +/* | |
| 362 | +** WEBPAGE: chat-delete | |
| 363 | +** | |
| 364 | +** Delete the chat entry identified by the name query parameter. | |
| 365 | +** Invoking fetch("chat-delete/"+msgid) from javascript in the client | |
| 366 | +** will delete a chat entry from the CHAT table. | |
| 367 | +** | |
| 368 | +** This routine both deletes the identified chat entry and also inserts | |
| 369 | +** a new entry with the current timestamp and with: | |
| 370 | +** | |
| 371 | +** * xmsg = NULL | |
| 372 | +** * file = NULL | |
| 373 | +** * mdel = The msgid of the row that was deleted | |
| 374 | +** | |
| 375 | +** This new entry will then be propagated to all listeners so that they | |
| 376 | +** will know to delete their copies of the message too. | |
| 377 | +*/ | |
| 378 | +void chat_delete_webpage(void){ | |
| 379 | + int mdel; | |
| 380 | + char *zOwner; | |
| 381 | + login_check_credentials(); | |
| 382 | + if( !g.perm.Chat ) return; | |
| 383 | + chat_create_tables(); | |
| 384 | + mdel = atoi(PD("name","0")); | |
| 385 | + zOwner = db_text(0, "SELECT xfrom FROM chat WHERE msgid=%d", mdel); | |
| 386 | + if( zOwner==0 ) return; | |
| 387 | + if( fossil_strcmp(zOwner, g.zLogin)!=0 && !g.perm.Admin ) return; | |
| 388 | + db_multi_exec( | |
| 389 | + "BEGIN;\n" | |
| 390 | + "DELETE FROM chat WHERE msgid=%d;\n" | |
| 391 | + "INSERT INTO chat(mtime, xfrom, mdel)" | |
| 392 | + " VALUES(julianday('now'), %Q, %d);\n" | |
| 393 | + "COMMIT;", | |
| 394 | + mdel, g.zLogin, mdel | |
| 395 | + ); | |
| 396 | +} | |
| 346 | 397 |
| --- src/chat.c | |
| +++ src/chat.c | |
| @@ -152,16 +152,17 @@ | |
| 152 | /* Definition of repository tables used by chat |
| 153 | */ |
| 154 | static const char zChatSchema1[] = |
| 155 | @ CREATE TABLE repository.chat( |
| 156 | @ msgid INTEGER PRIMARY KEY AUTOINCREMENT, |
| 157 | @ mtime JULIANDAY, |
| 158 | @ xfrom TEXT, |
| 159 | @ xmsg TEXT, |
| 160 | @ file BLOB, |
| 161 | @ fname TEXT, |
| 162 | @ fmime TEXT |
| 163 | @ ); |
| 164 | ; |
| 165 | |
| 166 | |
| 167 | /* |
| @@ -169,10 +170,12 @@ | |
| 169 | ** if they do not. |
| 170 | */ |
| 171 | static void chat_create_tables(void){ |
| 172 | if( !db_table_exists("repository","chat") ){ |
| 173 | db_multi_exec(zChatSchema1/*works-like:""*/); |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | /* |
| 178 | ** WEBPAGE: chat-send |
| @@ -235,18 +238,21 @@ | |
| 235 | ** | "uclr": text // Color string associated with the user |
| 236 | ** | "xmsg": text // HTML text of the message |
| 237 | ** | "fsize": integer // file attachment size in bytes |
| 238 | ** | "fname": text // Name of file attachment |
| 239 | ** | "fmime": text // MIME-type of file attachment |
| 240 | ** | } |
| 241 | ** | ] |
| 242 | ** | } |
| 243 | ** |
| 244 | ** The "fname" and "fmime" fields are only present if "fsize" is greater |
| 245 | ** than zero. The "xmsg" field may be an empty string if "fsize" is zero. |
| 246 | ** |
| 247 | ** The "msgid" values will be in increasing order. |
| 248 | */ |
| 249 | void chat_poll_webpage(void){ |
| 250 | Blob json; /* The json to be constructed and returned */ |
| 251 | sqlite3_int64 dataVersion; /* Data version. Used for polling. */ |
| 252 | sqlite3_int64 newDataVers; |
| @@ -258,11 +264,12 @@ | |
| 258 | if( !g.perm.Chat ) return; |
| 259 | chat_create_tables(); |
| 260 | cgi_set_content_type("text/json"); |
| 261 | dataVersion = db_int64(0, "PRAGMA data_version"); |
| 262 | db_prepare(&q1, |
| 263 | "SELECT msgid, datetime(mtime), xfrom, xmsg, length(file), fname, fmime" |
| 264 | " FROM chat" |
| 265 | " WHERE msgid>%d" |
| 266 | " ORDER BY msgid", |
| 267 | msgid |
| 268 | ); |
| @@ -272,13 +279,14 @@ | |
| 272 | while( db_step(&q1)==SQLITE_ROW ){ |
| 273 | int id = db_column_int(&q1, 0); |
| 274 | const char *zDate = db_column_text(&q1, 1); |
| 275 | const char *zFrom = db_column_text(&q1, 2); |
| 276 | const char *zRawMsg = db_column_text(&q1, 3); |
| 277 | const int nByte = db_column_int(&q1, 4); |
| 278 | const char *zFName = db_column_text(&q1, 5); |
| 279 | const char *zFMime = db_column_text(&q1, 6); |
| 280 | char *zMsg; |
| 281 | cnt++; |
| 282 | blob_append(&json, zSep, -1); |
| 283 | zSep = ",\n"; |
| 284 | blob_appendf(&json, "{\"msgid\":%d,\"mtime\":%!j,", id, zDate); |
| @@ -286,20 +294,25 @@ | |
| 286 | blob_appendf(&json, "\"uclr\":%!j,", hash_color(zFrom)); |
| 287 | |
| 288 | /* TBD: Convert the raw message into HTML, perhaps by running it |
| 289 | ** through a text formatter, or putting markup on @name phrases, |
| 290 | ** etc. */ |
| 291 | zMsg = mprintf("%h", zRawMsg); |
| 292 | blob_appendf(&json, "\"xmsg\":%!j,", zMsg); |
| 293 | fossil_free(zMsg); |
| 294 | |
| 295 | if( nByte==0 ){ |
| 296 | blob_appendf(&json, "\"fsize\":0}"); |
| 297 | }else{ |
| 298 | blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j}", |
| 299 | nByte, zFName, zFMime); |
| 300 | } |
| 301 | } |
| 302 | if( cnt ){ |
| 303 | blob_append(&json, "\n]}", 3); |
| 304 | cgi_set_content(&json); |
| 305 | break; |
| @@ -341,5 +354,43 @@ | |
| 341 | if( zMime==0 ) return; |
| 342 | db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid); |
| 343 | cgi_set_content_type(zMime); |
| 344 | cgi_set_content(&r); |
| 345 | } |
| 346 |
| --- src/chat.c | |
| +++ src/chat.c | |
| @@ -152,16 +152,17 @@ | |
| 152 | /* Definition of repository tables used by chat |
| 153 | */ |
| 154 | static const char zChatSchema1[] = |
| 155 | @ CREATE TABLE repository.chat( |
| 156 | @ msgid INTEGER PRIMARY KEY AUTOINCREMENT, |
| 157 | @ mtime JULIANDAY, -- Time for this entry - Julianday Zulu |
| 158 | @ xfrom TEXT, -- Login of the sender |
| 159 | @ xmsg TEXT, -- Raw, unformatted text of the message |
| 160 | @ file BLOB, -- Text of the uploaded file, or NULL |
| 161 | @ fname TEXT, -- Filename of the uploaded file, or NULL |
| 162 | @ fmime TEXT, -- MIMEType of the upload file, or NULL |
| 163 | @ mdel INT -- msgid of another message to delete |
| 164 | @ ); |
| 165 | ; |
| 166 | |
| 167 | |
| 168 | /* |
| @@ -169,10 +170,12 @@ | |
| 170 | ** if they do not. |
| 171 | */ |
| 172 | static void chat_create_tables(void){ |
| 173 | if( !db_table_exists("repository","chat") ){ |
| 174 | db_multi_exec(zChatSchema1/*works-like:""*/); |
| 175 | }else if( !db_table_has_column("repository","chat","mdel") ){ |
| 176 | db_multi_exec("ALTER TABLE chat ADD COLUMN mdel INT"); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | /* |
| 181 | ** WEBPAGE: chat-send |
| @@ -235,18 +238,21 @@ | |
| 238 | ** | "uclr": text // Color string associated with the user |
| 239 | ** | "xmsg": text // HTML text of the message |
| 240 | ** | "fsize": integer // file attachment size in bytes |
| 241 | ** | "fname": text // Name of file attachment |
| 242 | ** | "fmime": text // MIME-type of file attachment |
| 243 | ** | "mdel": integer // message id of prior message to delete |
| 244 | ** | } |
| 245 | ** | ] |
| 246 | ** | } |
| 247 | ** |
| 248 | ** The "fname" and "fmime" fields are only present if "fsize" is greater |
| 249 | ** than zero. The "xmsg" field may be an empty string if "fsize" is zero. |
| 250 | ** |
| 251 | ** The "msgid" values will be in increasing order. |
| 252 | ** |
| 253 | ** The "mdel" will only exist if "xmsg" is an empty string and "fsize" is zero. |
| 254 | */ |
| 255 | void chat_poll_webpage(void){ |
| 256 | Blob json; /* The json to be constructed and returned */ |
| 257 | sqlite3_int64 dataVersion; /* Data version. Used for polling. */ |
| 258 | sqlite3_int64 newDataVers; |
| @@ -258,11 +264,12 @@ | |
| 264 | if( !g.perm.Chat ) return; |
| 265 | chat_create_tables(); |
| 266 | cgi_set_content_type("text/json"); |
| 267 | dataVersion = db_int64(0, "PRAGMA data_version"); |
| 268 | db_prepare(&q1, |
| 269 | "SELECT msgid, datetime(mtime), xfrom, xmsg, length(file)," |
| 270 | " fname, fmime, mdel" |
| 271 | " FROM chat" |
| 272 | " WHERE msgid>%d" |
| 273 | " ORDER BY msgid", |
| 274 | msgid |
| 275 | ); |
| @@ -272,13 +279,14 @@ | |
| 279 | while( db_step(&q1)==SQLITE_ROW ){ |
| 280 | int id = db_column_int(&q1, 0); |
| 281 | const char *zDate = db_column_text(&q1, 1); |
| 282 | const char *zFrom = db_column_text(&q1, 2); |
| 283 | const char *zRawMsg = db_column_text(&q1, 3); |
| 284 | int nByte = db_column_int(&q1, 4); |
| 285 | const char *zFName = db_column_text(&q1, 5); |
| 286 | const char *zFMime = db_column_text(&q1, 6); |
| 287 | int iToDel = db_column_int(&q1, 7); |
| 288 | char *zMsg; |
| 289 | cnt++; |
| 290 | blob_append(&json, zSep, -1); |
| 291 | zSep = ",\n"; |
| 292 | blob_appendf(&json, "{\"msgid\":%d,\"mtime\":%!j,", id, zDate); |
| @@ -286,20 +294,25 @@ | |
| 294 | blob_appendf(&json, "\"uclr\":%!j,", hash_color(zFrom)); |
| 295 | |
| 296 | /* TBD: Convert the raw message into HTML, perhaps by running it |
| 297 | ** through a text formatter, or putting markup on @name phrases, |
| 298 | ** etc. */ |
| 299 | zMsg = mprintf("%h", zRawMsg ? zRawMsg : ""); |
| 300 | blob_appendf(&json, "\"xmsg\":%!j,", zMsg); |
| 301 | fossil_free(zMsg); |
| 302 | |
| 303 | if( nByte==0 ){ |
| 304 | blob_appendf(&json, "\"fsize\":0"); |
| 305 | }else{ |
| 306 | blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j", |
| 307 | nByte, zFName, zFMime); |
| 308 | } |
| 309 | if( iToDel ){ |
| 310 | blob_appendf(&json, ",\"mdel\":%d}", iToDel); |
| 311 | }else{ |
| 312 | blob_append(&json, "}", 1); |
| 313 | } |
| 314 | } |
| 315 | if( cnt ){ |
| 316 | blob_append(&json, "\n]}", 3); |
| 317 | cgi_set_content(&json); |
| 318 | break; |
| @@ -341,5 +354,43 @@ | |
| 354 | if( zMime==0 ) return; |
| 355 | db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid); |
| 356 | cgi_set_content_type(zMime); |
| 357 | cgi_set_content(&r); |
| 358 | } |
| 359 | |
| 360 | |
| 361 | /* |
| 362 | ** WEBPAGE: chat-delete |
| 363 | ** |
| 364 | ** Delete the chat entry identified by the name query parameter. |
| 365 | ** Invoking fetch("chat-delete/"+msgid) from javascript in the client |
| 366 | ** will delete a chat entry from the CHAT table. |
| 367 | ** |
| 368 | ** This routine both deletes the identified chat entry and also inserts |
| 369 | ** a new entry with the current timestamp and with: |
| 370 | ** |
| 371 | ** * xmsg = NULL |
| 372 | ** * file = NULL |
| 373 | ** * mdel = The msgid of the row that was deleted |
| 374 | ** |
| 375 | ** This new entry will then be propagated to all listeners so that they |
| 376 | ** will know to delete their copies of the message too. |
| 377 | */ |
| 378 | void chat_delete_webpage(void){ |
| 379 | int mdel; |
| 380 | char *zOwner; |
| 381 | login_check_credentials(); |
| 382 | if( !g.perm.Chat ) return; |
| 383 | chat_create_tables(); |
| 384 | mdel = atoi(PD("name","0")); |
| 385 | zOwner = db_text(0, "SELECT xfrom FROM chat WHERE msgid=%d", mdel); |
| 386 | if( zOwner==0 ) return; |
| 387 | if( fossil_strcmp(zOwner, g.zLogin)!=0 && !g.perm.Admin ) return; |
| 388 | db_multi_exec( |
| 389 | "BEGIN;\n" |
| 390 | "DELETE FROM chat WHERE msgid=%d;\n" |
| 391 | "INSERT INTO chat(mtime, xfrom, mdel)" |
| 392 | " VALUES(julianday('now'), %Q, %d);\n" |
| 393 | "COMMIT;", |
| 394 | mdel, g.zLogin, mdel |
| 395 | ); |
| 396 | } |
| 397 |