Fossil SCM

fossil-scm / src / moderate.c
Blame History Raw 230 lines
1
/*
2
** Copyright (c) 2012 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
**
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This file contains code used to deal with moderator actions for
19
** Wiki and Tickets.
20
*/
21
#include "config.h"
22
#include "moderate.h"
23
#include <assert.h>
24
25
/*
26
** Create a table to represent pending moderation requests, if the
27
** table does not already exist.
28
*/
29
void moderation_table_create(void){
30
db_multi_exec(
31
"CREATE TABLE IF NOT EXISTS repository.modreq(\n"
32
" objid INTEGER PRIMARY KEY,\n" /* Record pending approval */
33
" attachRid INT,\n" /* Object attached */
34
" tktid TEXT\n" /* Associated ticket id */
35
");\n"
36
);
37
}
38
39
/*
40
** Return TRUE if the modreq table exists
41
*/
42
int moderation_table_exists(void){
43
return db_table_exists("repository", "modreq");
44
}
45
46
/*
47
** Return TRUE if the object specified is being held for moderation.
48
*/
49
int moderation_pending(int rid){
50
static Stmt q;
51
int rc;
52
if( rid==0 || !moderation_table_exists() ) return 0;
53
db_static_prepare(&q, "SELECT 1 FROM modreq WHERE objid=:objid");
54
db_bind_int(&q, ":objid", rid);
55
rc = db_step(&q)==SQLITE_ROW;
56
db_reset(&q);
57
return rc;
58
}
59
60
/*
61
** If the rid object is being held for moderation, write out
62
** an "awaiting moderation" message and return true.
63
**
64
** If the object is not being held for moderation, simply return
65
** false without generating any output.
66
*/
67
int moderation_pending_www(int rid){
68
int pending = moderation_pending(rid);
69
if( pending ){
70
@ <span class="modpending">(Awaiting Moderator Approval)</span>
71
}
72
return pending;
73
}
74
75
76
/*
77
** Return TRUE if there any pending moderation requests.
78
*/
79
int moderation_needed(void){
80
if( !moderation_table_exists() ) return 0;
81
return db_exists("SELECT 1 FROM modreq");
82
}
83
84
/*
85
** Check to see if the object identified by RID is used for anything.
86
*/
87
static int object_used(int rid){
88
static const char *const aTabField[] = {
89
"modreq", "attachRid",
90
"mlink", "mid",
91
"mlink", "fid",
92
"tagxref", "srcid",
93
"tagxref", "rid",
94
};
95
int i;
96
for(i=0; i<count(aTabField); i+=2){
97
if( db_exists("SELECT 1 FROM \"%w\" WHERE \"%w\"=%d",
98
aTabField[i], aTabField[i+1], rid) ) return 1;
99
}
100
return 0;
101
}
102
103
/*
104
** Delete a moderation item given by objid
105
*/
106
void moderation_disapprove(int objid){
107
Stmt q;
108
char *zTktid;
109
int attachRid = 0;
110
int rid;
111
if( !moderation_pending(objid) ) return;
112
db_begin_transaction();
113
rid = objid;
114
while( rid && content_is_private(rid) ){
115
db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
116
while( db_step(&q)==SQLITE_ROW ){
117
int ridUser = db_column_int(&q, 0);
118
content_undelta(ridUser);
119
}
120
db_finalize(&q);
121
db_multi_exec(
122
"DELETE FROM blob WHERE rid=%d;"
123
"DELETE FROM delta WHERE rid=%d;"
124
"DELETE FROM event WHERE objid=%d;"
125
"DELETE FROM tagxref WHERE rid=%d;"
126
"DELETE FROM private WHERE rid=%d;"
127
"DELETE FROM attachment WHERE attachid=%d;",
128
rid, rid, rid, rid, rid, rid
129
);
130
if( db_table_exists("repository","forumpost") ){
131
db_multi_exec("DELETE FROM forumpost WHERE fpid=%d", rid);
132
}
133
zTktid = db_text(0, "SELECT tktid FROM modreq WHERE objid=%d", rid);
134
if( zTktid && zTktid[0] ){
135
ticket_rebuild_entry(zTktid);
136
fossil_free(zTktid);
137
}
138
attachRid = db_int(0, "SELECT attachRid FROM modreq WHERE objid=%d", rid);
139
if( rid==objid ){
140
db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
141
}
142
if( attachRid && object_used(attachRid) ) attachRid = 0;
143
admin_log("Disapproved moderation of rid %d.", rid);
144
rid = attachRid;
145
}
146
db_end_transaction(0);
147
}
148
149
/*
150
** Approve an object held for moderation.
151
*/
152
void moderation_approve(char class, int rid){
153
if( !moderation_pending(rid) ) return;
154
db_begin_transaction();
155
db_multi_exec(
156
"DELETE FROM private WHERE rid=%d;"
157
"INSERT OR IGNORE INTO unclustered VALUES(%d);"
158
"INSERT OR IGNORE INTO unsent VALUES(%d);",
159
rid, rid, rid
160
);
161
db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
162
admin_log("Approved moderation of rid %c-%d.", class, rid);
163
if( class!='a' ) search_doc_touch(class, rid, 0);
164
setup_incr_cfgcnt();
165
db_end_transaction(0);
166
}
167
168
/*
169
** WEBPAGE: modreq
170
**
171
** Show all pending moderation request
172
*/
173
void modreq_page(void){
174
Blob sql;
175
Stmt q;
176
177
login_check_credentials();
178
if( !g.perm.ModWiki && !g.perm.ModTkt && !g.perm.ModForum ){
179
login_needed(g.anon.ModWiki && g.anon.ModTkt && g.anon.ModForum);
180
return;
181
}
182
style_header("Pending Moderation Requests");
183
@ <h2>All Pending Moderation Requests</h2>
184
if( moderation_table_exists() ){
185
blob_init(&sql, timeline_query_for_www(), -1);
186
blob_append_sql(&sql,
187
" AND event.objid IN (SELECT objid FROM modreq)"
188
" ORDER BY event.mtime DESC"
189
);
190
db_prepare(&q, "%s", blob_sql_text(&sql));
191
www_print_timeline(&q, 0, 0, 0, 0, 0, 0, 0);
192
db_finalize(&q);
193
}
194
style_finish_page();
195
}
196
197
/*
198
** Disapproves any entries in the modreq table which belong to any
199
** user whose name is no longer found in the user table. This is only
200
** intended to be called after user deletion via /setup_uedit.
201
**
202
** To figure out whether a name exists it cross-references
203
** coalesce(event.euser, event.user) with user.login, limiting the
204
** selection to event entries where objid matches an entry in the
205
** modreq table.
206
**
207
** This is a no-op if called without g.perm.Admin permissions or if
208
** moderation_table_exists() returns false.
209
*/
210
void moderation_disapprove_for_missing_users(){
211
Stmt q;
212
if( !g.perm.Admin || !moderation_table_exists() ){
213
return;
214
}
215
db_begin_transaction();
216
db_prepare(&q,
217
"SELECT objid FROM event WHERE objid IN "
218
"(SELECT objid FROM modreq) "
219
"AND coalesce(euser,user) NOT IN "
220
"(SELECT login FROM user)"
221
);
222
while( db_step(&q)==SQLITE_ROW ){
223
int const objid = db_column_int(&q, 0);
224
moderation_disapprove(objid);
225
}
226
db_finalize(&q);
227
setup_incr_cfgcnt();
228
db_end_transaction(0);
229
}
230

Keyboard Shortcuts

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