Check-in [c109adadcf]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:main database Added table to help with syncing of submissions. Records submissions processed by the cli (accepted, rejected). IOW submissions we are done with. site database Dropped table `sync`, not used by the sync implementation. logic/submission Extended to use the new table web/site Implemented sync operation for submissions. Plus more docs on the relevant dataflow. Note: Sync and modified submission ops are not tested.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | f3f481018b-cgi-submission-support
Files: files | file ages | folders
SHA3-256: c109adadcf652d39f140e640c7e4ab2b725a0dca67fcddc9f80dcdfc939a4dfd
User & Date: andreask 2018-12-04 21:37:44.494
Context
2018-12-05
00:39
Reorganized the cli command structure - Centralized all four configuration commands (`show`, `take`, `store`, `limit`) under `config`. `config show` is default. - Centralized all five submission management commands (`submissions` (-> `list`), `submit` (-> `enter`), `accept`, `reject`, `rejected`) under `submission`. The renamed commands (Note `->`) have aliases under their old names. `submission list` is default. A new alias is `rejections`, for `submission rejected`. Added new command `drop` to remove entries from the rejection table (tests and other cruft). logic/submissions Changed `accept` and `reject` to handle not only the specific submission they are invoked with, but also all its duplicates, in terms of the referenced url. Support for a validator of rejections. New validator for rejections, used in command `drop`. check-in: 5472a887e3 user: andreask tags: f3f481018b-cgi-submission-support
2018-12-04
21:37
main database Added table to help with syncing of submissions. Records submissions processed by the cli (accepted, rejected). IOW submissions we are done with. site database Dropped table `sync`, not used by the sync implementation. logic/submission Extended to use the new table web/site Implemented sync operation for submissions. Plus more docs on the relevant dataflow. Note: Sync and modified submission ops are not tested. check-in: c109adadcf user: andreask tags: f3f481018b-cgi-submission-support
09:36
mirror-search Meta data fixes From `mirror-submit` Fake TERM setup stderr redirection mirror-submit Reworked to use the site database for all information needed, and as the sole destination for any submissions. Reorganized to have all database ops in a single transaction before starting to emit any page elements. Using new tables to cache url validation results, and url conversions into descriptions. Both ops reach out to external sites, making the submission script an indirect attack vector. Caching the results, even if only for a limited time (30 minutes fixed at the moment) will reduce the rate of access for any url going through the submission script to at most once per cache expiry interval. Add `clear` button to the form to reset url, vcs type, and description. It keeps session id, submitter name and email. site database Added two new tables for caching of url validation, and conversion to descriptions. Further fixed the bogus unique attribute on urls in submissions. Unique is url + session, not url alone. vcs github Tweak generation of description somewhat check-in: 969a4c87aa user: aku tags: f3f481018b-cgi-submission-support
Changes
Unified Diff Ignore Whitespace Patch
Changes to lib/db/db.tcl.
183
184
185
186
187
188
189

190
191
192

193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

217
218
219
220
221
222

223
224
225
226

227
228
229
230
231

232
233
234
235
236
237
238
239
240
    T rolodex

    # - -- --- ----- -------- -------------
    return
}

proc ::m::db::SETUP-201810092200 {} {

    # Added github VCS manager

    D m::db

    T^ version_control_system
    >+ 'github' 'GitHub'

    return
}

proc ::m::db::SETUP-201810111600 {} {

    # Added column `created` to `store_times`
    #
    # Notes on the recorded times:
    #
    # - Invariant: changed <= updated
    #   Because not every update causes a change.
    #
    # - Invariant: created <= changed
    #   Because a change can happen only after we have store
    #
    # - (created == changed)
    #   -> Never seen any change for this store.
    #
    # Overall
    #		created <= changed <= updated

    D m::db

    C store    INTEGER  NOT NULL  ^store PRIMARY KEY
    C created  INTEGER  NOT NULL
    C updated  INTEGER  NOT NULL
    C changed  INTEGER  NOT NULL
    < store_times  store updated updated changed
    #                    ^ use last update as fake creation

    return
}

proc ::m::db::SETUP-201810121600 {} {

    # Added mail configuration to the general state table

    set h {This is a semi-automated mail by @cmd@, on behalf of @sender@.}

    D m::db

    T^ state

    #                           -- Debugging
    > 'mail-debug'  '0'         ;# Bool. Activates low-level debugging in smtp/mime

    #                           -- SMTP configuration
    > 'mail-host'   'localhost' ;# Name of the mail-relay host to talk to
    > 'mail-port'   '25'        ;# Port where the mail-relay host accepts SMTP
    > 'mail-user'   'undefined' ;# account accepted by the mail-relay host







>



>







>

















>






>




>





>

<







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
    T rolodex

    # - -- --- ----- -------- -------------
    return
}

proc ::m::db::SETUP-201810092200 {} {
    debug.m/db {}
    # Added github VCS manager

    D m::db
    # - -- --- ----- -------- -------------
    T^ version_control_system
    >+ 'github' 'GitHub'

    return
}

proc ::m::db::SETUP-201810111600 {} {
    debug.m/db {}
    # Added column `created` to `store_times`
    #
    # Notes on the recorded times:
    #
    # - Invariant: changed <= updated
    #   Because not every update causes a change.
    #
    # - Invariant: created <= changed
    #   Because a change can happen only after we have store
    #
    # - (created == changed)
    #   -> Never seen any change for this store.
    #
    # Overall
    #		created <= changed <= updated

    D m::db
    # - -- --- ----- -------- -------------
    C store    INTEGER  NOT NULL  ^store PRIMARY KEY
    C created  INTEGER  NOT NULL
    C updated  INTEGER  NOT NULL
    C changed  INTEGER  NOT NULL
    < store_times  store updated updated changed
    #                    ^ use last update as fake creation

    return
}

proc ::m::db::SETUP-201810121600 {} {
    debug.m/db {}
    # Added mail configuration to the general state table

    set h {This is a semi-automated mail by @cmd@, on behalf of @sender@.}

    D m::db
    # - -- --- ----- -------- -------------
    T^ state

    #                           -- Debugging
    > 'mail-debug'  '0'         ;# Bool. Activates low-level debugging in smtp/mime

    #                           -- SMTP configuration
    > 'mail-host'   'localhost' ;# Name of the mail-relay host to talk to
    > 'mail-port'   '25'        ;# Port where the mail-relay host accepts SMTP
    > 'mail-user'   'undefined' ;# account accepted by the mail-relay host
248
249
250
251
252
253
254

255
256
257
258

259
260
261
262
263
264
265
266
267
268
269
270
271
272


273
274
275

276
277
278
279
280

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297

298
299
300

301
302
303
304
305
306
307
308
309
310
311
312
313

314
315
316

317
318
319
320
321
322
323
324
325
326
327
328
329
330

331
332
333

334
335
336

337
338
339
340

341
342
343
344

345
346
347
348
349
350
351
352
353
354
355
356

357
358
359

360
361
362
363
364
365
366

367
368
369
370
371
372

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391
392
393
394

395
396
397
398
399
400
401
402
403
404
405
406
407

















408
409
410
411
412
    #                            # Note: Template processing happens after the content
    #                            # is assembled, i.e. affects header and footer.

    return
}

proc ::m::db::SETUP-201810131603 {} {

    # Add tables for rejection mail content
    # (submission processing)

    D m::db

    I+
    C name      TEXT    NOT NULL UNIQUE
    C automail  INTEGER NOT NULL
    C isdefault INTEGER NOT NULL
    C text      TEXT    NOT NULL
    T reply

    set sm "It is spam"
    set om "It is off-topic here"
    set rm "It was intentionally removed before and we will not add it again"

    >+ 'spam'     0 1 '$sm' ;# default reason
    >+ 'offtopic' 1 0 '$om'
    >+ 'removed'  1 0 '$rm'


}

proc ::m::db::SETUP-201810141600 {} {

    # Add tables for external submissions
    # - submissions
    # - rejected submissions (for easy auto-rejection on replication)

    D m::db

    I+
    C url       TEXT NOT NULL UNIQUE
    C email     TEXT NOT NULL
    C submitter TEXT
    C sdate     INTEGER NOT NULL
    T submission
    X sdate

    I+
    C url    TEXT NOT NULL UNIQUE
    C reason TEXT NOT NULL
    T rejected

    return
}

proc ::m::db::SETUP-201810311600 {} {

    # Added column `size_kb` for store size to `store`.

    D m::db

    I+
    C vcs     INTEGER  NOT NULL  ^version_control_system
    C mset    INTEGER  NOT NULL  ^mirror_set
    C size_kb INTEGER  NOT NULL
    U vcs mset
    < store  id vcs mset '0'

    package require m::store
    m::store::InitialSizes
    return
}

proc ::m::db::SETUP-201811152300 {} {

    # Added site configuration to the general state table

    D m::db

    T^ state

    #                           -- Debugging
    > 'site-active'   '0'              ;# Site status (active or not)
    > 'site-store'    '~/.mirror/site' ;# Location where website is generated
    > 'site-mgr-mail' ''               ;# Mail address of the site manager
    > 'site-mgr-name' ''               ;# Name of the site manager
    > 'site-title'    'Mirror'         ;# Name of the site
    > 'site-url'      ''               ;# The url the site will be published at

    return
}

proc ::m::db::SETUP-201811162301 {} {

    # Added more site configuration to the general state table

    D m::db

    T^ state
    #                           -- Debugging
    > 'site-logo' '' ;# Path or url to the site logo.

    return
}

proc ::m::db::SETUP-201811202300 {} {

    # Added flag 'active' to repository.
    # Default: yes.

    D m::db

    I+
    C url    TEXT     NOT NULL  UNIQUE
    C vcs    INTEGER  NOT NULL  ^version_control_system
    C mset   INTEGER  NOT NULL  ^mirror_set
    C active INTEGER  NOT NULL
    < repository  id url vcs mset '1'
    X vcs mset

    return
}

proc ::m::db::SETUP-201811212300 {} {

    # Added `hg` to the set of supported VCS.

    D m::db

    T^ version_control_system
    >+ 'hg' 'Mercurial'

    return
}

proc ::m::db::SETUP-201811272200 {} {

    # Added optional columns `vcode` and `description` to the
    # submissions table. Initialized to empty. Further dropped unique
    # requirement from url, allowing multiple submissions of the same,
    # enabling fixing of description, vcode. Added index instead.

    D m::db

    I+
    C url         TEXT NOT NULL
    C vcode       TEXT
    C description TEXT
    C email       TEXT NOT NULL
    C submitter   TEXT
    C sdate       INTEGER NOT NULL
    < submission  id url '' '' email submitter sdate
    X sdate
    X url

    return
}

proc ::m::db::SETUP-201811282200 {} {

    # Added special column `session` to the submissions
    # table. Initialized to a value the other parts (cli, CGI) will
    # not generate.  Made url + session unique, i.e. primary key.  A
    # session is allowed to overwrite its submissions, but not the
    # submissions of other sessions.

    D m::db

    I+
    C session     TEXT NOT NULL
    C url         TEXT NOT NULL
    C vcode       TEXT
    C description TEXT
    C email       TEXT NOT NULL
    C submitter   TEXT
    C sdate       INTEGER NOT NULL
    U session url
    < submission  id ':lock:' url vcode description email submitter sdate
    X sdate
    X url


















    return
}

# # ## ### ##### ######## ############# #####################
return







>




>














>
>



>





>

















>



>













>



>

<












>



>



>




>




>












>



>







>






>















>







>













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
    #                            # Note: Template processing happens after the content
    #                            # is assembled, i.e. affects header and footer.

    return
}

proc ::m::db::SETUP-201810131603 {} {
    debug.m/db {}
    # Add tables for rejection mail content
    # (submission processing)

    D m::db
    # - -- --- ----- -------- -------------
    I+
    C name      TEXT    NOT NULL UNIQUE
    C automail  INTEGER NOT NULL
    C isdefault INTEGER NOT NULL
    C text      TEXT    NOT NULL
    T reply

    set sm "It is spam"
    set om "It is off-topic here"
    set rm "It was intentionally removed before and we will not add it again"

    >+ 'spam'     0 1 '$sm' ;# default reason
    >+ 'offtopic' 1 0 '$om'
    >+ 'removed'  1 0 '$rm'

    return
}

proc ::m::db::SETUP-201810141600 {} {
    debug.m/db {}
    # Add tables for external submissions
    # - submissions
    # - rejected submissions (for easy auto-rejection on replication)

    D m::db
    # - -- --- ----- -------- -------------
    I+
    C url       TEXT NOT NULL UNIQUE
    C email     TEXT NOT NULL
    C submitter TEXT
    C sdate     INTEGER NOT NULL
    T submission
    X sdate

    I+
    C url    TEXT NOT NULL UNIQUE
    C reason TEXT NOT NULL
    T rejected

    return
}

proc ::m::db::SETUP-201810311600 {} {
    debug.m/db {}
    # Added column `size_kb` for store size to `store`.

    D m::db
    # - -- --- ----- -------- -------------
    I+
    C vcs     INTEGER  NOT NULL  ^version_control_system
    C mset    INTEGER  NOT NULL  ^mirror_set
    C size_kb INTEGER  NOT NULL
    U vcs mset
    < store  id vcs mset '0'

    package require m::store
    m::store::InitialSizes
    return
}

proc ::m::db::SETUP-201811152300 {} {
    debug.m/db {}
    # Added site configuration to the general state table

    D m::db
    # - -- --- ----- -------- -------------
    T^ state

    #                           -- Debugging
    > 'site-active'   '0'              ;# Site status (active or not)
    > 'site-store'    '~/.mirror/site' ;# Location where website is generated
    > 'site-mgr-mail' ''               ;# Mail address of the site manager
    > 'site-mgr-name' ''               ;# Name of the site manager
    > 'site-title'    'Mirror'         ;# Name of the site
    > 'site-url'      ''               ;# The url the site will be published at

    return
}

proc ::m::db::SETUP-201811162301 {} {
    debug.m/db {}
    # Added more site configuration to the general state table

    D m::db
    # - -- --- ----- -------- -------------
    T^ state
    #                           -- Debugging
    > 'site-logo' '' ;# Path or url to the site logo.

    return
}

proc ::m::db::SETUP-201811202300 {} {
    debug.m/db {}
    # Added flag 'active' to repository.
    # Default: yes.

    D m::db
    # - -- --- ----- -------- -------------
    I+
    C url    TEXT     NOT NULL  UNIQUE
    C vcs    INTEGER  NOT NULL  ^version_control_system
    C mset   INTEGER  NOT NULL  ^mirror_set
    C active INTEGER  NOT NULL
    < repository  id url vcs mset '1'
    X vcs mset

    return
}

proc ::m::db::SETUP-201811212300 {} {
    debug.m/db {}
    # Added `hg` to the set of supported VCS.

    D m::db
    # - -- --- ----- -------- -------------
    T^ version_control_system
    >+ 'hg' 'Mercurial'

    return
}

proc ::m::db::SETUP-201811272200 {} {
    debug.m/db {}
    # Added optional columns `vcode` and `description` to the
    # submissions table. Initialized to empty. Further dropped unique
    # requirement from url, allowing multiple submissions of the same,
    # enabling fixing of description, vcode. Added index instead.

    D m::db
    # - -- --- ----- -------- -------------
    I+
    C url         TEXT NOT NULL
    C vcode       TEXT
    C description TEXT
    C email       TEXT NOT NULL
    C submitter   TEXT
    C sdate       INTEGER NOT NULL
    < submission  id url '' '' email submitter sdate
    X sdate
    X url

    return
}

proc ::m::db::SETUP-201811282200 {} {
    debug.m/db {}
    # Added special column `session` to the submissions
    # table. Initialized to a value the other parts (cli, CGI) will
    # not generate.  Made url + session unique, i.e. primary key.  A
    # session is allowed to overwrite its submissions, but not the
    # submissions of other sessions.

    D m::db
    # - -- --- ----- -------- -------------
    I+
    C session     TEXT NOT NULL
    C url         TEXT NOT NULL
    C vcode       TEXT
    C description TEXT
    C email       TEXT NOT NULL
    C submitter   TEXT
    C sdate       INTEGER NOT NULL
    U session url
    < submission  id ':lock:' url vcode description email submitter sdate
    X sdate
    X url

    return
}

proc ::m::db::SETUP-201811282200 {} {
    debug.m/db {}
    # Added sync helper table.
    # Remember all submissions handled locally (accepted or rejected),
    # for deletion from the CGI site database on next sync. Note that
    # we only need the key information, i.e. url + session id.

    D m::db
    # - -- --- ----- -------- -------------
    C session     TEXT NOT NULL
    C url         TEXT NOT NULL
    U session url
    T submission_handled

    return
}

# # ## ### ##### ######## ############# #####################
return
Changes to lib/db/site.tcl.
223
224
225
226
227
228
229










230
231
232
    < submission  \
	id session url vcode description email submitter when_submitted
    X when_submitted
    X url

    return
}











# # ## ### ##### ######## ############# #####################
return







>
>
>
>
>
>
>
>
>
>



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
    < submission  \
	id session url vcode description email submitter when_submitted
    X when_submitted
    X url

    return
}

proc ::m::site::SETUP-201812041400 {} {
    debug.m/db {}
    # Drop table `sync`, not used

    D m::site
    / sync
    
    return
}

# # ## ### ##### ######## ############# #####################
return
Changes to lib/logic/submission.tcl.
144
145
146
147
148
149
150
151












152
153
154
155
156
157
158
159
160
161
162
163
164
165
166












167
168
169
170



171
172
173
174
175
176
177
	FROM   rejected
	WHERE  url = :url
    }]
}

proc ::m::submission::accept {submission} {
    debug.m/submission {}
    m db onecolumn {












	DELETE
	FROM submission
	WHERE id = :submission
    }
    return
}

proc ::m::submission::reject {submission reason} {
    debug.m/submission {}
    set url [m db onecolum {
	SELECT url
	FROM  submission
	WHERE id = :submission
    }]
    m db eval {












	INSERT OR REPLACE
	INTO rejected
	VALUES ( NULL, :url, :reason )
	;



	DELETE
	FROM  submission
	WHERE id = :submission
    }
    return
}








|
>
>
>
>
>
>
>
>
>
>
>
>















>
>
>
>
>
>
>
>
>
>
>
>




>
>
>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
	FROM   rejected
	WHERE  url = :url
    }]
}

proc ::m::submission::accept {submission} {
    debug.m/submission {}
    m db eval {
	-- Phase I. Copy key information of the processed submission
	--          into the sync helper table
	INSERT
	INTO   submission_handled
	SELECT session
	,      url
	FROM   submission
	WHERE  id = :submission
	;
	--
	-- Phase II. Remove processed submission from the main table
	--
	DELETE
	FROM submission
	WHERE id = :submission
    }
    return
}

proc ::m::submission::reject {submission reason} {
    debug.m/submission {}
    set url [m db onecolum {
	SELECT url
	FROM  submission
	WHERE id = :submission
    }]
    m db eval {
	-- Phase I. Copy key information of the processed submission
	--          into the sync helper table
	INSERT
	INTO   submission_handled
	SELECT session
	,      url
	FROM   submission
	WHERE  id = :submission
	;
	--
	-- Phase II. Add rejection information to the associated table
	--
	INSERT OR REPLACE
	INTO rejected
	VALUES ( NULL, :url, :reason )
	;
	--
	-- Phase III.  Remove processed submission from the main table
	--
	DELETE
	FROM  submission
	WHERE id = :submission
    }
    return
}

Changes to lib/utils/setup.tcl.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
debug prefix db/setup {[debug caller] | }

# # ## ### ##### ######## ############# #####################
## Definition

namespace eval db::setup {
    namespace import ::db::track::it ; rename it track
    namespace export D C U T T^ I I+ > >+ X <
}

namespace eval db {
    namespace export setup
    namespace ensemble create
}








|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
debug prefix db/setup {[debug caller] | }

# # ## ### ##### ######## ############# #####################
## Definition

namespace eval db::setup {
    namespace import ::db::track::it ; rename it track
    namespace export D C U T T^ I I+ > >+ X < /
}

namespace eval db {
    namespace export setup
    namespace ensemble create
}

126
127
128
129
130
131
132






133
134
135
136
137
138
139
    append def "CREATE TABLE $table\n( "
    append def [join [Flat [PadR 1 [PadR 0 $thecols]]] "\n, "]
    append def "\n);"
    set thecols {}
    R $def
    return
}







proc db::setup::T^ {table} {
    debug.db/setup {}
    variable thetable $table
    return
}








>
>
>
>
>
>







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    append def "CREATE TABLE $table\n( "
    append def [join [Flat [PadR 1 [PadR 0 $thecols]]] "\n, "]
    append def "\n);"
    set thecols {}
    R $def
    return
}

proc db::setup::/ {table} {
    debug.db/setup {}
    R "DROP TABLE $table"
    return
}

proc db::setup::T^ {table} {
    debug.db/setup {}
    variable thetable $table
    return
}

Changes to lib/web/site.tcl.
407
408
409
410
411
412
413
414
415





416






















417
418


419


































420

































































421
422
423
424
425
426



427

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443



444
445
446
447
448
449
450
	file rename $stage $serve
    }
    return
}

proc ::m::web::site::Sync {} {
    debug.m/web/site {}
    lappend map @ [m::db::location get]
    #m::site eval [string map $map { ATTACH DATABASE '@' AS 'primary' }]




























    FillIndex
    FillRejected





































    #m::site eval { DETACH DATABASE 'primary' }

































































    return
}

proc ::m::web::site::FillRejected {} {
    debug.m/web/site {}




    m site eval { DELETE FROM rejected }

    m db eval {
	SELECT url
	,      reason
	FROM rejected
    } {
	m site eval {
	    INSERT
	    INTO rejected
	    VALUES ( NULL, :url, :reason )
	}
    }
    return
}

proc ::m::web::site::FillIndex {} {
    debug.m/web/site {}




    m site eval { DELETE FROM store_index }

    # m store search '' (inlined, simply all)
    m db eval {
	SELECT S.id      AS store
	,      N.name    AS mname







|
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>

>
















>
>
>







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
	file rename $stage $serve
    }
    return
}

proc ::m::web::site::Sync {} {
    debug.m/web/site {}

    # Data flows
    # - Main
    #   - mset_pending			local, no sync
    #   - reply				local, no sync
    #   - rolodex			local, no sync
    #   - schema			local, no sync
    #
    #   - mirror_set			[1] join/view pushed to site
    #   - name				[1] store_index, total replacement
    #   - repository			[1]
    #   - store				[1]
    #   - store_times			[1]
    #   - version_control_system	[1]
    #
    #   - rejected			push to site rejected, total replacement
    #   - submission			pull from site (insert or update)
    #   - submission_handled		push to site, deletions in submission
    #
    # - Site
    #   - cache_desc	local, no sync
    #   - cache_url	local, no sync
    #   - schema	local, no sync
    #
    #   - rejected	pulled from main rejected, total replacement
    #   - store_index	pulled from main [1], total replacement
    #
    #   - submission	pulled deletions from main (submission_handled)
    #			push remaining to main (insert or update)
    
    FillIndex
    FillRejected
    SyncSubmissions
    return
}

proc ::m::web::site::SyncSubmissions {} {
    debug.m/web/site {}

    # Syncing the submissions is easier than originally
    # thought. Because the flow is more restricted than thought, due
    # to the use of sessions.

    # 1. Submissions from CGI flow through site to main. Only
    #    deletions flow back, as the cli handles them in main.
    
    # 2. Submissions done in main, via the cli, have their own format
    #    for session identifiers which cannot overlap with sessions
    #    from the CGI. As such there is no need to push them to site,
    #    CGI will has no use for them when looking for pre-existing
    #    submissions. Anything needed there comes into site through
    #    the index and rejection tables.
    
    DropHandledSubmissions
    GetNewSubmissions
    return
}

proc ::m::web::site::GetNewSubmissions {} {
    debug.m/web/site {}
    
    # Phase II of syncing submissions between main and site.

    # Iterate over all the submissions in site. Update the entries in
    # main, or create new entries for them. It is the same logic
    # mirror-submit uses for the site database to distinguish and
    # perform add or edit (insert / update). Except this crosses two
    # databases.

    m site eval {
	SELECT session
	,      url
	,      vcode
	,      description
	,      email
	,      submitter
	,      when_submitted
	FROM submission
    } {
	if {[m db onecolumn {
	    SELECT count (*)
	    FROM  submission
	    WHERE url     = :url
	    AND   session = :session
	}]} {
	    # exists, update
	    m db eval {
		UPDATE submission
		SET vcode       = :vcode
		,   description = :desc
		,   email       = :email
		,   submitter   = :submitter
		,   sdate       = :when_submitted
		WHERE url     = :url
		AND   session = :session
	    }
	} else {
	    # not known, insert
	    m db eval {
		INSERT
		INTO submission
		VALUES ( NULL, :session, :url, :vcode, :desc, :email, :submitter, :when_submitted )
	    }
	}
    }
    
    return
}

proc ::m::web::site::DropHandledSubmissions {} {
    debug.m/web/site {}

    # Phase I of syncing submissions between main and site.

    # Iterate over all the submissions marked as handled in main and
    # remove them from site. From the main helper table also.

    m db eval {
	SELECT url
	,      session
	FROM submission_handled
    } {
	m site eval {
	    DELETE
	    FROM submission
	    WHERE url     = :url
	    AND   session = :session
	}
    }

    m db eval {
	DELETE
	FROM submission_handled
    }
    
    return
}

proc ::m::web::site::FillRejected {} {
    debug.m/web/site {}

    # Copy current state of url rejections from main to site database.
    # Implemented as `delete all old ; insert all new`.
    
    m site eval { DELETE FROM rejected }
    
    m db eval {
	SELECT url
	,      reason
	FROM rejected
    } {
	m site eval {
	    INSERT
	    INTO rejected
	    VALUES ( NULL, :url, :reason )
	}
    }
    return
}

proc ::m::web::site::FillIndex {} {
    debug.m/web/site {}

    # Copy current state of known stores and remotes from main to site
    # database. Implemented as `delete all old ; insert all new`.

    m site eval { DELETE FROM store_index }

    # m store search '' (inlined, simply all)
    m db eval {
	SELECT S.id      AS store
	,      N.name    AS mname