Fossil SCM

Improved chat messages for the chat-timeline-robot.

drh 2022-09-15 15:35 trunk
Commit 974cf3667c4f741b9093b707e951ce2743c25bcdb29321ad3242fc4c17521ef1
3 files changed +42 -14 +78 +5 -1
+42 -14
--- src/alerts.c
+++ src/alerts.c
@@ -140,10 +140,31 @@
140140
db_multi_exec(
141141
"ALTER TABLE repository.pending_alert"
142142
" ADD COLUMN sentMod BOOLEAN DEFAULT false;"
143143
);
144144
}
145
+
146
+/*
147
+** Process deferred alert events
148
+*/
149
+static int alert_process_deferred_triggers(void){
150
+ if( db_table_exists("temp","deferred_chat_events")
151
+ && db_table_exists("repository","chat")
152
+ ){
153
+ const char *zChatUser = db_get("chat-timeline-user", 0);
154
+ if( zChatUser && zChatUser[0] ){
155
+ db_multi_exec(
156
+ "INSERT INTO chat(mtime,xfrom,xmsg)"
157
+ " SELECT julianday(), %Q,"
158
+ " chat_msg_from_event(type, objid, user, comment)\n"
159
+ " FROM deferred_chat_events;\n",
160
+ zChatUser
161
+ );
162
+ }
163
+ }
164
+ return 0;
165
+}
145166
146167
/*
147168
** Enable triggers that automatically populate the pending_alert
148169
** table. (Later:) Also add triggers that automatically relay timeline
149170
** events to chat, if chat is configured for that.
@@ -158,24 +179,31 @@
158179
" SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n"
159180
" ON CONFLICT(eventId) DO NOTHING;\n"
160181
"END;"
161182
);
162183
}
163
- if( db_table_exists("repository","chat") ){
164
- const char *zChatUser = db_get("chat-timeline-user", 0);
165
- if( zChatUser && zChatUser[0] ){
166
- db_multi_exec(
167
- "CREATE TRIGGER temp.chat_trigger1\n"
168
- "AFTER INSERT ON repository.event BEGIN\n"
169
- " INSERT INTO chat(mtime,xfrom,xmsg)"
170
- " SELECT julianday(), %Q,"
171
- " format('[%%.12s]: %%s', blob.uuid, new.comment)"
172
- " FROM blob WHERE rid=new.objid;\n"
173
- "END;\n",
174
- zChatUser
175
- );
176
- }
184
+ if( db_table_exists("repository","chat")
185
+ && db_get("chat-timeline-user", "")[0]!=0
186
+ ){
187
+ /* Record events that will be relayed to chat, but do not relay
188
+ ** them immediately, as the chat_msg_from_event() function requires
189
+ ** that TAGXREF be up-to-date, and that has not happened yet when
190
+ ** the insert into the EVENT table occurs. */
191
+ db_multi_exec(
192
+ "CREATE TABLE temp.deferred_chat_events(\n"
193
+ " type TEXT,\n"
194
+ " objid INT,\n"
195
+ " user TEXT,\n"
196
+ " comment TEXT\n"
197
+ ");\n"
198
+ "CREATE TRIGGER temp.chat_trigger1\n"
199
+ "AFTER INSERT ON repository.event BEGIN\n"
200
+ " INSERT INTO deferred_chat_events"
201
+ " VALUES(new.type,new.objid,new.user,new.comment);\n"
202
+ "END;\n"
203
+ );
204
+ db_commit_hook(alert_process_deferred_triggers, 1);
177205
}
178206
}
179207
180208
/*
181209
** Disable triggers the event_pending and chat triggers.
182210
--- src/alerts.c
+++ src/alerts.c
@@ -140,10 +140,31 @@
140 db_multi_exec(
141 "ALTER TABLE repository.pending_alert"
142 " ADD COLUMN sentMod BOOLEAN DEFAULT false;"
143 );
144 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
146 /*
147 ** Enable triggers that automatically populate the pending_alert
148 ** table. (Later:) Also add triggers that automatically relay timeline
149 ** events to chat, if chat is configured for that.
@@ -158,24 +179,31 @@
158 " SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n"
159 " ON CONFLICT(eventId) DO NOTHING;\n"
160 "END;"
161 );
162 }
163 if( db_table_exists("repository","chat") ){
164 const char *zChatUser = db_get("chat-timeline-user", 0);
165 if( zChatUser && zChatUser[0] ){
166 db_multi_exec(
167 "CREATE TRIGGER temp.chat_trigger1\n"
168 "AFTER INSERT ON repository.event BEGIN\n"
169 " INSERT INTO chat(mtime,xfrom,xmsg)"
170 " SELECT julianday(), %Q,"
171 " format('[%%.12s]: %%s', blob.uuid, new.comment)"
172 " FROM blob WHERE rid=new.objid;\n"
173 "END;\n",
174 zChatUser
175 );
176 }
 
 
 
 
 
 
 
177 }
178 }
179
180 /*
181 ** Disable triggers the event_pending and chat triggers.
182
--- src/alerts.c
+++ src/alerts.c
@@ -140,10 +140,31 @@
140 db_multi_exec(
141 "ALTER TABLE repository.pending_alert"
142 " ADD COLUMN sentMod BOOLEAN DEFAULT false;"
143 );
144 }
145
146 /*
147 ** Process deferred alert events
148 */
149 static int alert_process_deferred_triggers(void){
150 if( db_table_exists("temp","deferred_chat_events")
151 && db_table_exists("repository","chat")
152 ){
153 const char *zChatUser = db_get("chat-timeline-user", 0);
154 if( zChatUser && zChatUser[0] ){
155 db_multi_exec(
156 "INSERT INTO chat(mtime,xfrom,xmsg)"
157 " SELECT julianday(), %Q,"
158 " chat_msg_from_event(type, objid, user, comment)\n"
159 " FROM deferred_chat_events;\n",
160 zChatUser
161 );
162 }
163 }
164 return 0;
165 }
166
167 /*
168 ** Enable triggers that automatically populate the pending_alert
169 ** table. (Later:) Also add triggers that automatically relay timeline
170 ** events to chat, if chat is configured for that.
@@ -158,24 +179,31 @@
179 " SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n"
180 " ON CONFLICT(eventId) DO NOTHING;\n"
181 "END;"
182 );
183 }
184 if( db_table_exists("repository","chat")
185 && db_get("chat-timeline-user", "")[0]!=0
186 ){
187 /* Record events that will be relayed to chat, but do not relay
188 ** them immediately, as the chat_msg_from_event() function requires
189 ** that TAGXREF be up-to-date, and that has not happened yet when
190 ** the insert into the EVENT table occurs. */
191 db_multi_exec(
192 "CREATE TABLE temp.deferred_chat_events(\n"
193 " type TEXT,\n"
194 " objid INT,\n"
195 " user TEXT,\n"
196 " comment TEXT\n"
197 ");\n"
198 "CREATE TRIGGER temp.chat_trigger1\n"
199 "AFTER INSERT ON repository.event BEGIN\n"
200 " INSERT INTO deferred_chat_events"
201 " VALUES(new.type,new.objid,new.user,new.comment);\n"
202 "END;\n"
203 );
204 db_commit_hook(alert_process_deferred_triggers, 1);
205 }
206 }
207
208 /*
209 ** Disable triggers the event_pending and chat triggers.
210
+78
--- src/chat.c
+++ src/chat.c
@@ -879,10 +879,88 @@
879879
}
880880
blob_init(&chatDb, (const char*)pDb, (int)szDb);
881881
cgi_set_content_type("application/x-sqlite3");
882882
cgi_set_content(&chatDb);
883883
}
884
+
885
+/*
886
+** SQL Function: chat_msg_from_event(TYPE,OBJID,USER,MSG)
887
+**
888
+** This function returns HTML text that describes an entry from the EVENT
889
+** table (that is, a timeline event) for display in chat. Parameters:
890
+**
891
+** TYPE The event type. 'ci', 'w', 't', 'g', and so forth
892
+** OBJID EVENT.OBJID
893
+** USER coalesce(EVENT.EUSER,EVENT.USER)
894
+** MSG coalesce(EVENT.ECOMMENT, EVENT.COMMENT)
895
+**
896
+** This function is intended to be called by the temp.chat_trigger1 trigger
897
+** which is created by alert_create_trigger() routine.
898
+*/
899
+void chat_msg_from_event(
900
+ sqlite3_context *context,
901
+ int argc,
902
+ sqlite3_value **argv
903
+){
904
+ const char *zType = (const char*)sqlite3_value_text(argv[0]);
905
+ int rid = sqlite3_value_int(argv[1]);
906
+ const char *zUser = (const char*)sqlite3_value_text(argv[2]);
907
+ const char *zMsg = (const char*)sqlite3_value_text(argv[3]);
908
+ char *zRes = 0;
909
+
910
+ if( zType==0 || zUser==0 || zMsg==0 ) return;
911
+ if( zType[0]=='c' ){
912
+ /* Check-ins */
913
+ char *zBranch;
914
+ char *zUuid;
915
+
916
+ zBranch = db_text(0,
917
+ "SELECT value FROM tagxref"
918
+ " WHERE tagxref.rid=%d"
919
+ " AND tagxref.tagid=%d"
920
+ " AND tagxref.tagtype>0",
921
+ rid, TAG_BRANCH);
922
+ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
923
+ zRes = mprintf("%W (check-in: <a href='%R/info/%S'>%S</a>, "
924
+ "user: <a href='%R/timeline?u=%t&c=%S'>%h</a>, "
925
+ "branch: <a href='%R/timeline?r=%t&c=%S'>%h</a>)",
926
+ zMsg,
927
+ zUuid, zUuid,
928
+ zUser, zUuid, zUser,
929
+ zBranch, zUuid, zBranch
930
+ );
931
+ fossil_free(zBranch);
932
+ fossil_free(zUuid);
933
+ }else if( zType[0]=='w' ){
934
+ /* Wiki page changes */
935
+ char *zUuid;
936
+ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
937
+ wiki_hyperlink_override(zUuid);
938
+ if( zMsg[0]=='-' ){
939
+ zRes = mprintf("Delete wiki page <a href='%R/whistory?name=%t'>%h</a>",
940
+ zMsg+1, zMsg+1);
941
+ }else if( zMsg[0]=='+' ){
942
+ zRes = mprintf("Added wiki page <a href='%R/whistory?name=%t'>%h</a>",
943
+ zMsg+1, zMsg+1);
944
+ }else if( zMsg[0]==':' ){
945
+ zRes = mprintf("<a href='%R/wdiff?id=%!S'>Changes</a> to wiki page "
946
+ "<a href='%R/whistory?name=%t'>%h</a>",
947
+ zUuid, zMsg+1, zMsg+1);
948
+ }else{
949
+ zRes = mprintf("%W", zMsg);
950
+ }
951
+ wiki_hyperlink_override(0);
952
+ fossil_free(zUuid);
953
+ }else{
954
+ /* Anything else */
955
+ zRes = mprintf("%W", zMsg);
956
+ }
957
+ if( zRes ){
958
+ sqlite3_result_text(context, zRes, -1, fossil_free);
959
+ }
960
+}
961
+
884962
885963
/*
886964
** COMMAND: chat
887965
**
888966
** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
889967
--- src/chat.c
+++ src/chat.c
@@ -879,10 +879,88 @@
879 }
880 blob_init(&chatDb, (const char*)pDb, (int)szDb);
881 cgi_set_content_type("application/x-sqlite3");
882 cgi_set_content(&chatDb);
883 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
884
885 /*
886 ** COMMAND: chat
887 **
888 ** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
889
--- src/chat.c
+++ src/chat.c
@@ -879,10 +879,88 @@
879 }
880 blob_init(&chatDb, (const char*)pDb, (int)szDb);
881 cgi_set_content_type("application/x-sqlite3");
882 cgi_set_content(&chatDb);
883 }
884
885 /*
886 ** SQL Function: chat_msg_from_event(TYPE,OBJID,USER,MSG)
887 **
888 ** This function returns HTML text that describes an entry from the EVENT
889 ** table (that is, a timeline event) for display in chat. Parameters:
890 **
891 ** TYPE The event type. 'ci', 'w', 't', 'g', and so forth
892 ** OBJID EVENT.OBJID
893 ** USER coalesce(EVENT.EUSER,EVENT.USER)
894 ** MSG coalesce(EVENT.ECOMMENT, EVENT.COMMENT)
895 **
896 ** This function is intended to be called by the temp.chat_trigger1 trigger
897 ** which is created by alert_create_trigger() routine.
898 */
899 void chat_msg_from_event(
900 sqlite3_context *context,
901 int argc,
902 sqlite3_value **argv
903 ){
904 const char *zType = (const char*)sqlite3_value_text(argv[0]);
905 int rid = sqlite3_value_int(argv[1]);
906 const char *zUser = (const char*)sqlite3_value_text(argv[2]);
907 const char *zMsg = (const char*)sqlite3_value_text(argv[3]);
908 char *zRes = 0;
909
910 if( zType==0 || zUser==0 || zMsg==0 ) return;
911 if( zType[0]=='c' ){
912 /* Check-ins */
913 char *zBranch;
914 char *zUuid;
915
916 zBranch = db_text(0,
917 "SELECT value FROM tagxref"
918 " WHERE tagxref.rid=%d"
919 " AND tagxref.tagid=%d"
920 " AND tagxref.tagtype>0",
921 rid, TAG_BRANCH);
922 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
923 zRes = mprintf("%W (check-in: <a href='%R/info/%S'>%S</a>, "
924 "user: <a href='%R/timeline?u=%t&c=%S'>%h</a>, "
925 "branch: <a href='%R/timeline?r=%t&c=%S'>%h</a>)",
926 zMsg,
927 zUuid, zUuid,
928 zUser, zUuid, zUser,
929 zBranch, zUuid, zBranch
930 );
931 fossil_free(zBranch);
932 fossil_free(zUuid);
933 }else if( zType[0]=='w' ){
934 /* Wiki page changes */
935 char *zUuid;
936 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
937 wiki_hyperlink_override(zUuid);
938 if( zMsg[0]=='-' ){
939 zRes = mprintf("Delete wiki page <a href='%R/whistory?name=%t'>%h</a>",
940 zMsg+1, zMsg+1);
941 }else if( zMsg[0]=='+' ){
942 zRes = mprintf("Added wiki page <a href='%R/whistory?name=%t'>%h</a>",
943 zMsg+1, zMsg+1);
944 }else if( zMsg[0]==':' ){
945 zRes = mprintf("<a href='%R/wdiff?id=%!S'>Changes</a> to wiki page "
946 "<a href='%R/whistory?name=%t'>%h</a>",
947 zUuid, zMsg+1, zMsg+1);
948 }else{
949 zRes = mprintf("%W", zMsg);
950 }
951 wiki_hyperlink_override(0);
952 fossil_free(zUuid);
953 }else{
954 /* Anything else */
955 zRes = mprintf("%W", zMsg);
956 }
957 if( zRes ){
958 sqlite3_result_text(context, zRes, -1, fossil_free);
959 }
960 }
961
962
963 /*
964 ** COMMAND: chat
965 **
966 ** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
967
+5 -1
--- src/db.c
+++ src/db.c
@@ -125,11 +125,11 @@
125125
int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
126126
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
127127
struct sCommitHook {
128128
int (*xHook)(void); /* Functions to call at db_end_transaction() */
129129
int sequence; /* Call functions in sequence order */
130
- } aHook[5];
130
+ } aHook[6];
131131
char *azDeleteOnFail[3]; /* Files to delete on a failure */
132132
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
133133
int nBeforeCommit; /* Number of entries in azBeforeCommit */
134134
int nPriorChanges; /* sqlite3_total_changes() at transaction start */
135135
const char *zStartFile; /* File in which transaction was started */
@@ -1464,10 +1464,14 @@
14641464
db_protected_setting_func, 0, 0);
14651465
sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
14661466
db_win_reserved_func,0,0);
14671467
sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
14681468
url_nouser_func,0,0);
1469
+ sqlite3_create_function(db, "chat_msg_from_event", 4,
1470
+ SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
1471
+ chat_msg_from_event, 0, 0);
1472
+
14691473
}
14701474
14711475
#if USE_SEE
14721476
/*
14731477
** This is a pointer to the saved database encryption key string.
14741478
--- src/db.c
+++ src/db.c
@@ -125,11 +125,11 @@
125 int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
126 int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
127 struct sCommitHook {
128 int (*xHook)(void); /* Functions to call at db_end_transaction() */
129 int sequence; /* Call functions in sequence order */
130 } aHook[5];
131 char *azDeleteOnFail[3]; /* Files to delete on a failure */
132 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
133 int nBeforeCommit; /* Number of entries in azBeforeCommit */
134 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
135 const char *zStartFile; /* File in which transaction was started */
@@ -1464,10 +1464,14 @@
1464 db_protected_setting_func, 0, 0);
1465 sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
1466 db_win_reserved_func,0,0);
1467 sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
1468 url_nouser_func,0,0);
 
 
 
 
1469 }
1470
1471 #if USE_SEE
1472 /*
1473 ** This is a pointer to the saved database encryption key string.
1474
--- src/db.c
+++ src/db.c
@@ -125,11 +125,11 @@
125 int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
126 int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
127 struct sCommitHook {
128 int (*xHook)(void); /* Functions to call at db_end_transaction() */
129 int sequence; /* Call functions in sequence order */
130 } aHook[6];
131 char *azDeleteOnFail[3]; /* Files to delete on a failure */
132 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
133 int nBeforeCommit; /* Number of entries in azBeforeCommit */
134 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
135 const char *zStartFile; /* File in which transaction was started */
@@ -1464,10 +1464,14 @@
1464 db_protected_setting_func, 0, 0);
1465 sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
1466 db_win_reserved_func,0,0);
1467 sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
1468 url_nouser_func,0,0);
1469 sqlite3_create_function(db, "chat_msg_from_event", 4,
1470 SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
1471 chat_msg_from_event, 0, 0);
1472
1473 }
1474
1475 #if USE_SEE
1476 /*
1477 ** This is a pointer to the saved database encryption key string.
1478

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button