Fossil SCM

Work toward pages to enter forum posts. This is an incremental check-in to save state and definitely does not work.

drh 2018-07-24 19:44 forum-v2
Commit 7b5099ea44a5b03e3bfc72e22f2c869084db73b4ae73cd1d0a0f35efff88f6d2
+9 -5
--- src/cgi.c
+++ src/cgi.c
@@ -1111,23 +1111,27 @@
11111111
return zDefault;
11121112
}
11131113
11141114
/*
11151115
** Return the value of a CGI parameter with leading and trailing
1116
-** spaces removed.
1116
+** spaces removed and with internal \r\n changed to just \n
11171117
*/
11181118
char *cgi_parameter_trimmed(const char *zName, const char *zDefault){
11191119
const char *zIn;
1120
- char *zOut;
1121
- int i;
1120
+ char *zOut, c;
1121
+ int i, j;
11221122
zIn = cgi_parameter(zName, 0);
11231123
if( zIn==0 ) zIn = zDefault;
11241124
if( zIn==0 ) return 0;
11251125
while( fossil_isspace(zIn[0]) ) zIn++;
11261126
zOut = fossil_strdup(zIn);
1127
- for(i=0; zOut[i]; i++){}
1128
- while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
1127
+ for(i=j=0; (c = zOut[i])!=0; i++){
1128
+ if( c=='\r' && zOut[i+1]=='\n' ) continue;
1129
+ zOut[j++] = c;
1130
+ }
1131
+ zOut[j] = 0;
1132
+ while( i>0 && fossil_isspace(zOut[j-1]) ) zOut[--j] = 0;
11291133
return zOut;
11301134
}
11311135
11321136
/*
11331137
** Return true if the CGI parameter zName exists and is not equal to 0,
11341138
--- src/cgi.c
+++ src/cgi.c
@@ -1111,23 +1111,27 @@
1111 return zDefault;
1112 }
1113
1114 /*
1115 ** Return the value of a CGI parameter with leading and trailing
1116 ** spaces removed.
1117 */
1118 char *cgi_parameter_trimmed(const char *zName, const char *zDefault){
1119 const char *zIn;
1120 char *zOut;
1121 int i;
1122 zIn = cgi_parameter(zName, 0);
1123 if( zIn==0 ) zIn = zDefault;
1124 if( zIn==0 ) return 0;
1125 while( fossil_isspace(zIn[0]) ) zIn++;
1126 zOut = fossil_strdup(zIn);
1127 for(i=0; zOut[i]; i++){}
1128 while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
 
 
 
 
1129 return zOut;
1130 }
1131
1132 /*
1133 ** Return true if the CGI parameter zName exists and is not equal to 0,
1134
--- src/cgi.c
+++ src/cgi.c
@@ -1111,23 +1111,27 @@
1111 return zDefault;
1112 }
1113
1114 /*
1115 ** Return the value of a CGI parameter with leading and trailing
1116 ** spaces removed and with internal \r\n changed to just \n
1117 */
1118 char *cgi_parameter_trimmed(const char *zName, const char *zDefault){
1119 const char *zIn;
1120 char *zOut, c;
1121 int i, j;
1122 zIn = cgi_parameter(zName, 0);
1123 if( zIn==0 ) zIn = zDefault;
1124 if( zIn==0 ) return 0;
1125 while( fossil_isspace(zIn[0]) ) zIn++;
1126 zOut = fossil_strdup(zIn);
1127 for(i=j=0; (c = zOut[i])!=0; i++){
1128 if( c=='\r' && zOut[i+1]=='\n' ) continue;
1129 zOut[j++] = c;
1130 }
1131 zOut[j] = 0;
1132 while( i>0 && fossil_isspace(zOut[j-1]) ) zOut[--j] = 0;
1133 return zOut;
1134 }
1135
1136 /*
1137 ** Return true if the CGI parameter zName exists and is not equal to 0,
1138
+124 -3
--- src/forum.c
+++ src/forum.c
@@ -76,19 +76,140 @@
7676
return;
7777
}
7878
forum_thread_chronological(froot);
7979
style_footer();
8080
}
81
+
82
+/*
83
+** Return true if a forum post should be moderated.
84
+*/
85
+static int forum_need_moderation(void){
86
+ return !g.perm.WrTForum && !g.perm.ModForum && P("domod")==0;
87
+}
88
+
89
+/*
90
+** Add a new Forum Post artifact to the repository.
91
+*/
92
+static void forum_post(
93
+ const char *zTitle, /* Title. NULL for replies */
94
+ int iInReplyTo, /* Post replying to. 0 for new threads */
95
+ int iEdit, /* Post being edited, or zero for a new post */
96
+ const char *zUser, /* Username. NULL means use login name */
97
+ const char *zMimetype, /* Mimetype of content. */
98
+ const char *zContent /* Content */
99
+){
100
+ Blob x, cksum;
101
+ char *zDate;
102
+ schema_forum();
103
+ blob_init(&x, 0, 0);
104
+ zDate = date_in_standard_format("now");
105
+ blob_appendf(&x, "D %s\n", zDate);
106
+ fossil_free(zDate);
107
+ if( zTitle ){
108
+ blob_appendf(&x, "H %F\n", zTitle);
109
+ }else{
110
+ char *zG = db_text(0,
111
+ "SELECT uuid FROM blob, forumpost"
112
+ " WHERE blob.rid==forumpost.froot"
113
+ " AND forumpost.fpid=%d", iInReplyTo);
114
+ char *zI;
115
+ if( zG==0 ) goto forum_post_error;
116
+ blob_appendf(&x, "G %s\n", zG);
117
+ fossil_free(zG);
118
+ zI = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iInReplyTo);
119
+ if( zI==0 ) goto forum_post_error;
120
+ blob_appendf(&x, "I %s\n", zI);
121
+ fossil_free(zI);
122
+ }
123
+ if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
124
+ blob_appendf(&x, "N %s\n", zMimetype);
125
+ }
126
+ if( iEdit>0 ){
127
+ char *zP = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iEdit);
128
+ if( zP==0 ) goto forum_post_error;
129
+ blob_appendf(&x, "P %s\n", zP);
130
+ fossil_free(zP);
131
+ }
132
+ if( zUser==0 ){
133
+ if( login_is_nobody() ){
134
+ zUser = "anonymous";
135
+ }else{
136
+ zUser = login_name();
137
+ }
138
+ }
139
+ blob_appendf(&x, "U %F\n", zUser);
140
+ blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent);
141
+ md5sum_blob(&x, &cksum);
142
+ blob_appendf(&x, "Z %b\n", &cksum);
143
+ blob_reset(&cksum);
144
+ if( P("dryrun") ){
145
+ @ <pre>%h(blob_str(&x))</pre><hr>
146
+ }else{
147
+ wiki_put(&x, 0, forum_need_moderation());
148
+ return;
149
+ }
150
+
151
+forum_post_error:
152
+ blob_reset(&x);
153
+}
154
+
155
+/*
156
+** Render a forum post for display
157
+*/
158
+void forum_render(const char *zMimetype, const char *zContent){
159
+ Blob x;
160
+ blob_init(&x, zContent, -1);
161
+ wiki_render_by_mimetype(&x, zMimetype);
162
+ blob_reset(&x);
163
+}
81164
82165
/*
83166
** WEBPAGE: forumnew
167
+** WEBPAGE: test-forumnew
84168
**
85
-** Start a new forum thread.
169
+** Start a new forum thread. The /test-forumnew works just like
170
+** /forumnew except that it provides additional controls for testing
171
+** and debugging.
86172
*/
87173
void forumnew_page(void){
88
- style_header("Pending");
89
- @ TBD...
174
+ const char *zTitle = PDT("t","");
175
+ const char *zMimetype = PD("mt","text/x-fossil-wiki");
176
+ const char *zContent = PDT("x","");
177
+ login_check_credentials();
178
+ if( !g.perm.WrForum ){
179
+ login_needed(g.anon.WrForum);
180
+ return;
181
+ }
182
+ if( P("submit") ){
183
+ forum_post(zTitle, 0, 0, 0, zMimetype, zContent);
184
+ }
185
+ if( P("preview") ){
186
+ @ <h1>%h(zTitle)</h1>
187
+ forum_render(zMimetype, zContent);
188
+ @ <hr>
189
+ }
190
+ style_header("New Forum Thread");
191
+ @ <form action="%R/%s(g.zPath)" method="POST">
192
+ @ Title: <input type="input" name="t" value="%h(zTitle)" size="50"><br>
193
+ @ Markup style:
194
+ mimetype_option_menu(zMimetype);
195
+ @ <br><textarea name="x" class="wikiedit" cols="80" \
196
+ @ rows="25" wrap="virtual">%h(zContent)</textarea><br>
197
+ @ <input type="submit" name="preview" value="Preview">
198
+ if( P("preview") ){
199
+ @ <input type="submit" name="submit" value="Submit">
200
+ }else{
201
+ @ <input type="submit" name="submit" value="Submit" disabled>
202
+ }
203
+ if( g.zPath[0]=='t' ){
204
+ /* For the test-forumnew page add these extra debugging controls */
205
+ @ <br><label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
206
+ @ Dry run</label>
207
+ @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
208
+ @ Require moderator approval</label>
209
+ }
210
+ @ </form>
90211
style_footer();
91212
}
92213
93214
/*
94215
** WEBPAGE: forumreply
95216
--- src/forum.c
+++ src/forum.c
@@ -76,19 +76,140 @@
76 return;
77 }
78 forum_thread_chronological(froot);
79 style_footer();
80 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
82 /*
83 ** WEBPAGE: forumnew
 
84 **
85 ** Start a new forum thread.
 
 
86 */
87 void forumnew_page(void){
88 style_header("Pending");
89 @ TBD...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90 style_footer();
91 }
92
93 /*
94 ** WEBPAGE: forumreply
95
--- src/forum.c
+++ src/forum.c
@@ -76,19 +76,140 @@
76 return;
77 }
78 forum_thread_chronological(froot);
79 style_footer();
80 }
81
82 /*
83 ** Return true if a forum post should be moderated.
84 */
85 static int forum_need_moderation(void){
86 return !g.perm.WrTForum && !g.perm.ModForum && P("domod")==0;
87 }
88
89 /*
90 ** Add a new Forum Post artifact to the repository.
91 */
92 static void forum_post(
93 const char *zTitle, /* Title. NULL for replies */
94 int iInReplyTo, /* Post replying to. 0 for new threads */
95 int iEdit, /* Post being edited, or zero for a new post */
96 const char *zUser, /* Username. NULL means use login name */
97 const char *zMimetype, /* Mimetype of content. */
98 const char *zContent /* Content */
99 ){
100 Blob x, cksum;
101 char *zDate;
102 schema_forum();
103 blob_init(&x, 0, 0);
104 zDate = date_in_standard_format("now");
105 blob_appendf(&x, "D %s\n", zDate);
106 fossil_free(zDate);
107 if( zTitle ){
108 blob_appendf(&x, "H %F\n", zTitle);
109 }else{
110 char *zG = db_text(0,
111 "SELECT uuid FROM blob, forumpost"
112 " WHERE blob.rid==forumpost.froot"
113 " AND forumpost.fpid=%d", iInReplyTo);
114 char *zI;
115 if( zG==0 ) goto forum_post_error;
116 blob_appendf(&x, "G %s\n", zG);
117 fossil_free(zG);
118 zI = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iInReplyTo);
119 if( zI==0 ) goto forum_post_error;
120 blob_appendf(&x, "I %s\n", zI);
121 fossil_free(zI);
122 }
123 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
124 blob_appendf(&x, "N %s\n", zMimetype);
125 }
126 if( iEdit>0 ){
127 char *zP = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iEdit);
128 if( zP==0 ) goto forum_post_error;
129 blob_appendf(&x, "P %s\n", zP);
130 fossil_free(zP);
131 }
132 if( zUser==0 ){
133 if( login_is_nobody() ){
134 zUser = "anonymous";
135 }else{
136 zUser = login_name();
137 }
138 }
139 blob_appendf(&x, "U %F\n", zUser);
140 blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent);
141 md5sum_blob(&x, &cksum);
142 blob_appendf(&x, "Z %b\n", &cksum);
143 blob_reset(&cksum);
144 if( P("dryrun") ){
145 @ <pre>%h(blob_str(&x))</pre><hr>
146 }else{
147 wiki_put(&x, 0, forum_need_moderation());
148 return;
149 }
150
151 forum_post_error:
152 blob_reset(&x);
153 }
154
155 /*
156 ** Render a forum post for display
157 */
158 void forum_render(const char *zMimetype, const char *zContent){
159 Blob x;
160 blob_init(&x, zContent, -1);
161 wiki_render_by_mimetype(&x, zMimetype);
162 blob_reset(&x);
163 }
164
165 /*
166 ** WEBPAGE: forumnew
167 ** WEBPAGE: test-forumnew
168 **
169 ** Start a new forum thread. The /test-forumnew works just like
170 ** /forumnew except that it provides additional controls for testing
171 ** and debugging.
172 */
173 void forumnew_page(void){
174 const char *zTitle = PDT("t","");
175 const char *zMimetype = PD("mt","text/x-fossil-wiki");
176 const char *zContent = PDT("x","");
177 login_check_credentials();
178 if( !g.perm.WrForum ){
179 login_needed(g.anon.WrForum);
180 return;
181 }
182 if( P("submit") ){
183 forum_post(zTitle, 0, 0, 0, zMimetype, zContent);
184 }
185 if( P("preview") ){
186 @ <h1>%h(zTitle)</h1>
187 forum_render(zMimetype, zContent);
188 @ <hr>
189 }
190 style_header("New Forum Thread");
191 @ <form action="%R/%s(g.zPath)" method="POST">
192 @ Title: <input type="input" name="t" value="%h(zTitle)" size="50"><br>
193 @ Markup style:
194 mimetype_option_menu(zMimetype);
195 @ <br><textarea name="x" class="wikiedit" cols="80" \
196 @ rows="25" wrap="virtual">%h(zContent)</textarea><br>
197 @ <input type="submit" name="preview" value="Preview">
198 if( P("preview") ){
199 @ <input type="submit" name="submit" value="Submit">
200 }else{
201 @ <input type="submit" name="submit" value="Submit" disabled>
202 }
203 if( g.zPath[0]=='t' ){
204 /* For the test-forumnew page add these extra debugging controls */
205 @ <br><label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
206 @ Dry run</label>
207 @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
208 @ Require moderator approval</label>
209 }
210 @ </form>
211 style_footer();
212 }
213
214 /*
215 ** WEBPAGE: forumreply
216
+1 -1
--- src/manifest.c
+++ src/manifest.c
@@ -2466,11 +2466,11 @@
24662466
blob_reset(&comment);
24672467
}
24682468
if( p->type==CFTYPE_FORUM ){
24692469
int froot, fprev, firt;
24702470
schema_forum();
2471
- froot = uuid_to_rid(p->zThreadRoot, 1);
2471
+ froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : p->rid;
24722472
fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
24732473
firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
24742474
db_multi_exec(
24752475
"INSERT INTO forumpost(fpid,froot,fprev,firt,fmtime)"
24762476
"VALUES(%d,%d,nullif(%d,0),nullif(%d,0),%.17g)",
24772477
--- src/manifest.c
+++ src/manifest.c
@@ -2466,11 +2466,11 @@
2466 blob_reset(&comment);
2467 }
2468 if( p->type==CFTYPE_FORUM ){
2469 int froot, fprev, firt;
2470 schema_forum();
2471 froot = uuid_to_rid(p->zThreadRoot, 1);
2472 fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
2473 firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
2474 db_multi_exec(
2475 "INSERT INTO forumpost(fpid,froot,fprev,firt,fmtime)"
2476 "VALUES(%d,%d,nullif(%d,0),nullif(%d,0),%.17g)",
2477
--- src/manifest.c
+++ src/manifest.c
@@ -2466,11 +2466,11 @@
2466 blob_reset(&comment);
2467 }
2468 if( p->type==CFTYPE_FORUM ){
2469 int froot, fprev, firt;
2470 schema_forum();
2471 froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : p->rid;
2472 fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
2473 firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
2474 db_multi_exec(
2475 "INSERT INTO forumpost(fpid,froot,fprev,firt,fmtime)"
2476 "VALUES(%d,%d,nullif(%d,0),nullif(%d,0),%.17g)",
2477
+5 -5
--- src/schema.c
+++ src/schema.c
@@ -556,15 +556,15 @@
556556
** is created on-demand whenever the manifest parser encounters
557557
** a forum-post artifact.
558558
*/
559559
static const char zForumSchema[] =
560560
@ CREATE TABLE repository.forumpost(
561
-@ fpid INTEGER PRIMARY KEY; -- BLOB.rid for the artifact
562
-@ froot INT; -- fpid of the thread root
563
-@ fprev INT; -- Previous version of this same post
564
-@ firt INT; -- This post is in-reply-to
565
-@ fmtime REAL; -- When posted. Julian day
561
+@ fpid INTEGER PRIMARY KEY, -- BLOB.rid for the artifact
562
+@ froot INT, -- fpid of the thread root
563
+@ fprev INT, -- Previous version of this same post
564
+@ firt INT, -- This post is in-reply-to
565
+@ fmtime REAL -- When posted. Julian day
566566
@ );
567567
@ CREATE INDEX repository.forumthread ON forumpost(froot);
568568
;
569569
570570
/* Create the forum-post schema if it does not already exist */
571571
--- src/schema.c
+++ src/schema.c
@@ -556,15 +556,15 @@
556 ** is created on-demand whenever the manifest parser encounters
557 ** a forum-post artifact.
558 */
559 static const char zForumSchema[] =
560 @ CREATE TABLE repository.forumpost(
561 @ fpid INTEGER PRIMARY KEY; -- BLOB.rid for the artifact
562 @ froot INT; -- fpid of the thread root
563 @ fprev INT; -- Previous version of this same post
564 @ firt INT; -- This post is in-reply-to
565 @ fmtime REAL; -- When posted. Julian day
566 @ );
567 @ CREATE INDEX repository.forumthread ON forumpost(froot);
568 ;
569
570 /* Create the forum-post schema if it does not already exist */
571
--- src/schema.c
+++ src/schema.c
@@ -556,15 +556,15 @@
556 ** is created on-demand whenever the manifest parser encounters
557 ** a forum-post artifact.
558 */
559 static const char zForumSchema[] =
560 @ CREATE TABLE repository.forumpost(
561 @ fpid INTEGER PRIMARY KEY, -- BLOB.rid for the artifact
562 @ froot INT, -- fpid of the thread root
563 @ fprev INT, -- Previous version of this same post
564 @ firt INT, -- This post is in-reply-to
565 @ fmtime REAL -- When posted. Julian day
566 @ );
567 @ CREATE INDEX repository.forumthread ON forumpost(froot);
568 ;
569
570 /* Create the forum-post schema if it does not already exist */
571
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -426,11 +426,11 @@
426426
}
427427
428428
/*
429429
** Write a wiki artifact into the repository
430430
*/
431
-static void wiki_put(Blob *pWiki, int parent, int needMod){
431
+void wiki_put(Blob *pWiki, int parent, int needMod){
432432
int nrid;
433433
if( !needMod ){
434434
nrid = content_put_ex(pWiki, 0, 0, 0, 0);
435435
if( parent) content_deltify(parent, &nrid, 1, 0);
436436
}else{
437437
--- src/wiki.c
+++ src/wiki.c
@@ -426,11 +426,11 @@
426 }
427
428 /*
429 ** Write a wiki artifact into the repository
430 */
431 static void wiki_put(Blob *pWiki, int parent, int needMod){
432 int nrid;
433 if( !needMod ){
434 nrid = content_put_ex(pWiki, 0, 0, 0, 0);
435 if( parent) content_deltify(parent, &nrid, 1, 0);
436 }else{
437
--- src/wiki.c
+++ src/wiki.c
@@ -426,11 +426,11 @@
426 }
427
428 /*
429 ** Write a wiki artifact into the repository
430 */
431 void wiki_put(Blob *pWiki, int parent, int needMod){
432 int nrid;
433 if( !needMod ){
434 nrid = content_put_ex(pWiki, 0, 0, 0, 0);
435 if( parent) content_deltify(parent, &nrid, 1, 0);
436 }else{
437

Keyboard Shortcuts

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