AsmBB

Check-in [8b5016ce39]
Login

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

Overview
Comment:Implemented rendered HTML cache. Development time measured: 78 minutes. All changed are in this checkin.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | HTMLCache
Files: files | file ages | folders
SHA1: 8b5016ce39246bea66cb5d0da379a1e7e9125c80
User & Date: johnfound 2017-01-05 18:02:15
Context
2017-01-05
19:31:26
Admin permissions for !render_all function. Fixed bug in the avatar images browser caching. check-in: d86f802707 user: johnfound tags: HTMLCache
18:02:15
Implemented rendered HTML cache. Development time measured: 78 minutes. All changed are in this checkin. check-in: 8b5016ce39 user: johnfound tags: HTMLCache
2017-01-03
22:45:40
Fixed two bugs in the registration form: A XSS and a crash on invalid e-mail. check-in: 18ace583a3 user: johnfound tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to source/commands.asm.

160
161
162
163
164
165
166


167
168
169
170
171
172
173

        mov     [.mime], mimeText
        jmp     .get_file_if_newer

.check_file_type:

        stdcall StrExtractExt, [.filename]


        push    eax

        stdcall GetMimeType, eax
        stdcall StrDel ; from the stack
        jc      .analize_uri

        mov     [.mime], eax







>
>







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

        mov     [.mime], mimeText
        jmp     .get_file_if_newer

.check_file_type:

        stdcall StrExtractExt, [.filename]
        jc      .analize_uri

        push    eax

        stdcall GetMimeType, eax
        stdcall StrDel ; from the stack
        jc      .analize_uri

        mov     [.mime], eax

Changes to source/create.sql.

75
76
77
78
79
80
81
82

83
84
85
86
87
88
89
create table Posts (
  id          integer primary key autoincrement,
  threadID    integer references Threads(id) on delete cascade,
  userID      integer references Users(id) on delete cascade,

  postTime    integer,  -- based on postTime the posts are sorted in the thread.
  ReadCount   integer,
  Content     text

);


create index idxPosts_UserID   on Posts (userID);
create index idxPosts_ThreadID on Posts (threadID);
create index idxPostsThreadUser on posts(threadid, userid);








|
>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
create table Posts (
  id          integer primary key autoincrement,
  threadID    integer references Threads(id) on delete cascade,
  userID      integer references Users(id) on delete cascade,

  postTime    integer,  -- based on postTime the posts are sorted in the thread.
  ReadCount   integer,
  Content     text,
  Rendered    text
);


create index idxPosts_UserID   on Posts (userID);
create index idxPosts_ThreadID on Posts (threadID);
create index idxPostsThreadUser on posts(threadid, userid);

Changes to source/edit.asm.

1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31



sqlReadPost    text "select P.id, T.caption, P.content as source, ?2 as Ticket from Posts P left join Threads T on T.id = P.threadID where P.id = ?1"
sqlEditedPost  text "select P.id, T.caption, ?3 as source, ?2 as Ticket from Posts P left join Threads T on T.id = P.threadID where P.id = ?1"
sqlSavePost    text "update Posts set content = substr( ?1, 1, ?3 ), postTime = strftime('%s','now') where id = ?2"
sqlGetPostUser text "select userID, threadID from Posts where id = ?"


proc EditUserMessage, .pSpecial
.stmt dd ?

.source   dd ?

.ticket   dd ?

.res      dd ?
.threadID dd ?
.userID   dd ?

begin
        pushad

        xor     ebx, ebx
        mov     [.source], ebx

        mov     [.ticket], ebx

        mov     esi, [.pSpecial]

        stdcall StrNew
        mov     edi, eax






|







>











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33



sqlReadPost    text "select P.id, T.caption, P.content as source, ?2 as Ticket from Posts P left join Threads T on T.id = P.threadID where P.id = ?1"
sqlEditedPost  text "select P.id, T.caption, ?3 as source, ?2 as Ticket from Posts P left join Threads T on T.id = P.threadID where P.id = ?1"
sqlSavePost    text "update Posts set content = ?1, rendered = ?2, postTime = strftime('%s','now') where id = ?3"
sqlGetPostUser text "select userID, threadID from Posts where id = ?"


proc EditUserMessage, .pSpecial
.stmt dd ?

.source   dd ?
.rendered dd ?
.ticket   dd ?

.res      dd ?
.threadID dd ?
.userID   dd ?

begin
        pushad

        xor     ebx, ebx
        mov     [.source], ebx
        mov     [.rendered], ebx
        mov     [.ticket], ebx

        mov     esi, [.pSpecial]

        stdcall StrNew
        mov     edi, eax

158
159
160
161
162
163
164
165
166











167
168
169
170
171
172
173
174











175
176
177
178
179
180
181
        cmp     ebx, SQLITE_DONE
        jne     .end_save               ; the transaction does not begin.


        lea     eax, [.stmt]
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlSavePost, -1, eax, 0

        cinvoke sqliteBindInt, [.stmt], 2, [esi+TSpecialParams.page_num]
        cinvoke sqliteBindInt, [.stmt], 3, LIMIT_POST_LENGTH












        stdcall StrPtr, [.source]

        mov     ecx, [eax+string.len]
        test    ecx, ecx
        jz      .error_write

        cinvoke sqliteBindText, [.stmt], 1, eax, ecx, SQLITE_STATIC












        cinvoke sqliteStep, [.stmt]
        mov     ebx, eax
        cinvoke sqliteFinalize, [.stmt]

        cmp     ebx, SQLITE_DONE
        jne     .error_write            ; strange write fault.







<
|
>
>
>
>
>
>
>
>
>
>
>








>
>
>
>
>
>
>
>
>
>
>







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
        cmp     ebx, SQLITE_DONE
        jne     .end_save               ; the transaction does not begin.


        lea     eax, [.stmt]
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlSavePost, -1, eax, 0


        cinvoke sqliteBindInt, [.stmt], 3, [esi+TSpecialParams.page_num]

        stdcall StrByteUtf8, [.source], LIMIT_POST_LENGTH
        stdcall StrTrim, [.source], eax

; render the source

        stdcall StrDup, [.source]
        stdcall FormatPostText, eax
        mov     [.rendered], eax

; bind the source

        stdcall StrPtr, [.source]

        mov     ecx, [eax+string.len]
        test    ecx, ecx
        jz      .error_write

        cinvoke sqliteBindText, [.stmt], 1, eax, ecx, SQLITE_STATIC

; bind the html

        stdcall StrPtr, [.rendered]

        mov     ecx, [eax+string.len]
        test    ecx, ecx
        jz      .error_write

        cinvoke sqliteBindText, [.stmt], 2, eax, ecx, SQLITE_STATIC


        cinvoke sqliteStep, [.stmt]
        mov     ebx, eax
        cinvoke sqliteFinalize, [.stmt]

        cmp     ebx, SQLITE_DONE
        jne     .error_write            ; strange write fault.
214
215
216
217
218
219
220

221
222
223
224
225
226
227

        stdcall ClearTicket, [esi+TSpecialParams.session]
        stc


.finish:
        stdcall StrDel, [.source]

        stdcall StrDel, [.ticket]
        mov     [esp+4*regEAX], edi
        popad
        return


.error_post_id:







>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251

        stdcall ClearTicket, [esi+TSpecialParams.session]
        stc


.finish:
        stdcall StrDel, [.source]
        stdcall StrDel, [.rendered]
        stdcall StrDel, [.ticket]
        mov     [esp+4*regEAX], edi
        popad
        return


.error_post_id:

Changes to source/engine.fpr.

cannot compute difference between binary files

Changes to source/post.asm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
LIMIT_POST_LENGTH = 16*1024
LIMIT_POST_CAPTION = 512
LIMIT_TAG_DESCRIPTION = 1024


cNewPostForm   text "form_new_post"
cNewThreadForm text "form_new_thread"

sqlSelectConst text "select ? as slug, ? as caption, ? as source, ? as ticket, ? as tags"

sqlGetQuote   text "select U.nick, P.content from Posts P left join Users U on U.id = P.userID where P.id = ?"

sqlInsertPost text "insert into Posts ( ThreadID, UserID, PostTime, Content, ReadCount) values (?, ?, strftime('%s','now'), ?, 0)"
sqlUpdateThreads text "update Threads set LastChanged = strftime('%s','now') where id = ?"
sqlInsertThread  text "insert into Threads ( Caption ) values ( ? )"
sqlSetThreadSlug text "update Threads set slug = ? where id = ?"


proc PostUserMessage, .pSpecial
.stmt  dd ?
.stmt2 dd ?

.fPreview dd ?

.slug     dd ?

.caption  dd ?
.tags     dd ?
.count    dd ?

.source   dd ?

.ticket   dd ?

.postID   dd ?
.threadID dd ?

begin
        pushad

        xor     eax, eax
        mov     [.fPreview], eax  ; preview by default when handling GET requests.
        mov     [.slug], eax
        mov     [.source], eax

        mov     [.caption], eax
        mov     [.tags], eax
        mov     [.ticket], eax
        mov     [.stmt], eax
        mov     [.stmt2], eax

        mov     esi, [.pSpecial]












|


















>












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
LIMIT_POST_LENGTH = 16*1024
LIMIT_POST_CAPTION = 512
LIMIT_TAG_DESCRIPTION = 1024


cNewPostForm   text "form_new_post"
cNewThreadForm text "form_new_thread"

sqlSelectConst text "select ? as slug, ? as caption, ? as source, ? as ticket, ? as tags"

sqlGetQuote   text "select U.nick, P.content from Posts P left join Users U on U.id = P.userID where P.id = ?"

sqlInsertPost text "insert into Posts ( ThreadID, UserID, PostTime, Content, Rendered, ReadCount) values (?, ?, strftime('%s','now'), ?, ?, 0)"
sqlUpdateThreads text "update Threads set LastChanged = strftime('%s','now') where id = ?"
sqlInsertThread  text "insert into Threads ( Caption ) values ( ? )"
sqlSetThreadSlug text "update Threads set slug = ? where id = ?"


proc PostUserMessage, .pSpecial
.stmt  dd ?
.stmt2 dd ?

.fPreview dd ?

.slug     dd ?

.caption  dd ?
.tags     dd ?
.count    dd ?

.source   dd ?
.rendered dd ?
.ticket   dd ?

.postID   dd ?
.threadID dd ?

begin
        pushad

        xor     eax, eax
        mov     [.fPreview], eax  ; preview by default when handling GET requests.
        mov     [.slug], eax
        mov     [.source], eax
        mov     [.rendered], eax
        mov     [.caption], eax
        mov     [.tags], eax
        mov     [.ticket], eax
        mov     [.stmt], eax
        mov     [.stmt2], eax

        mov     esi, [.pSpecial]
462
463
464
465
466
467
468









469
470
471
472
473
474
475
476










477
478
479
480
481
482
483
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlInsertPost, -1, eax, 0

        cinvoke sqliteBindInt, [.stmt], 1, ebx
        cinvoke sqliteBindInt, [.stmt], 2, [esi+TSpecialParams.userID]

        cmp     [.source], 0
        je      .error_invalid_content










        stdcall StrPtr, [.source]

        mov     ecx, [eax+string.len]
        test    ecx, ecx
        jz      .error_invalid_content

        cinvoke sqliteBindText, [.stmt], 3, eax, ecx, SQLITE_STATIC











        cinvoke sqliteStep, [.stmt]
        cmp     eax, SQLITE_DONE
        jne     .rollback

        cinvoke sqliteFinalize, [.stmt]








>
>
>
>
>
>
>
>
>








>
>
>
>
>
>
>
>
>
>







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
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlInsertPost, -1, eax, 0

        cinvoke sqliteBindInt, [.stmt], 1, ebx
        cinvoke sqliteBindInt, [.stmt], 2, [esi+TSpecialParams.userID]

        cmp     [.source], 0
        je      .error_invalid_content

; render the source

        stdcall StrDup, [.source]
        stdcall FormatPostText, eax
        mov     [.rendered], eax


; bind the source

        stdcall StrPtr, [.source]

        mov     ecx, [eax+string.len]
        test    ecx, ecx
        jz      .error_invalid_content

        cinvoke sqliteBindText, [.stmt], 3, eax, ecx, SQLITE_STATIC

; bind the rendered htmlt

        stdcall StrPtr, [.rendered]
        mov     ecx, [eax+string.len]
        test    ecx, ecx
        jz      .error_invalid_content

        cinvoke sqliteBindText, [.stmt], 4, eax, ecx, SQLITE_STATIC


        cinvoke sqliteStep, [.stmt]
        cmp     eax, SQLITE_DONE
        jne     .rollback

        cinvoke sqliteFinalize, [.stmt]

517
518
519
520
521
522
523

524
525
526
527
528
529
530
        mov     eax, [.pSpecial]
        stdcall ClearTicket, [eax+TSpecialParams.session]
        stc

.finish:
        stdcall StrDel, [.slug]
        stdcall StrDel, [.source]

        stdcall StrDel, [.caption]
        stdcall StrDel, [.tags]
        stdcall StrDel, [.ticket]

        mov     [esp+4*regEAX], edi
        popad
        return







>







538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
        mov     eax, [.pSpecial]
        stdcall ClearTicket, [eax+TSpecialParams.session]
        stc

.finish:
        stdcall StrDel, [.slug]
        stdcall StrDel, [.source]
        stdcall StrDel, [.rendered]
        stdcall StrDel, [.caption]
        stdcall StrDel, [.tags]
        stdcall StrDel, [.ticket]

        mov     [esp+4*regEAX], edi
        popad
        return

Changes to source/render.asm.

124
125
126
127
128
129
130



131
132
133
134
135
136
137
; first check for special names

        stdcall StrMatchPatternNoCase, "special:*", edi
        jc      .process_special

        stdcall StrMatchPatternNoCase, "minimag:*", edi
        jc      .process_minimag




        stdcall StrMatchPatternNoCase, "case:*", edi
        jc      .process_case

        stdcall StrMatchPatternNoCase, "and:*", edi
        jc      .process_and








>
>
>







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
; first check for special names

        stdcall StrMatchPatternNoCase, "special:*", edi
        jc      .process_special

        stdcall StrMatchPatternNoCase, "minimag:*", edi
        jc      .process_minimag

        stdcall StrMatchPatternNoCase, "html:*", edi
        jc      .process_html

        stdcall StrMatchPatternNoCase, "case:*", edi
        jc      .process_case

        stdcall StrMatchPatternNoCase, "and:*", edi
        jc      .process_and

973
974
975
976
977
978
979











980
981
982
983
984
985
986

        stdcall __DoProcessTemplate2, edi, [.sql_stmt], [.pSpecial], FALSE

        stdcall FormatPostText, eax
        jmp     .return_value














;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


.process_case:

        stdcall StrSplit, edi, 5







>
>
>
>
>
>
>
>
>
>
>







976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000

        stdcall __DoProcessTemplate2, edi, [.sql_stmt], [.pSpecial], FALSE

        stdcall FormatPostText, eax
        jmp     .return_value


.process_html:

        stdcall StrSplit, edi, 5
        stdcall StrDel, edi
        stdcall StrClipSpacesL, eax
        mov     edi, eax

        stdcall __DoProcessTemplate2, edi, [.sql_stmt], [.pSpecial], FALSE

        jmp     .return_value


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


.process_case:

        stdcall StrSplit, edi, 5
1691
1692
1693
1694
1695
1696
1697































































1698
1699
1700
1701
1702
1703
1704
.finish:
        popad
        return

endp







































































; Print the envoronment and post data to STDERR. ONLY for debugging purposes, especially for POST requests.







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







1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
.finish:
        popad
        return

endp





sqlSelectAllPosts text "select id, content from Posts"
sqlUpdateHTML     text "update Posts set Rendered = ?1 where id = ?2"

proc RenderAll, .pSpecial
.stmt dd ?
.stmt2 dd ?
begin
        pushad

        mov     esi, [.pSpecial]

        lea     eax, [.stmt]
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlSelectAllPosts, -1, eax, 0

        lea     eax, [.stmt2]
        cinvoke sqlitePrepare_v2, [hMainDatabase], sqlUpdateHTML, -1, eax, 0

.loop:
        cinvoke sqliteStep, [.stmt]
        cmp     eax, SQLITE_ROW
        jne     .finish

        cinvoke sqliteColumnInt, [.stmt], 0
        mov     ebx, eax

        cinvoke sqliteColumnText, [.stmt], 1
        stdcall StrDupMem, eax

        stdcall FormatPostText, eax
        mov     edi, eax

        cinvoke sqliteBindInt, [.stmt2], 2, ebx

        stdcall StrPtr, edi
        cinvoke sqliteBindText, [.stmt2], 1, eax, [eax+string.len], SQLITE_STATIC

        cinvoke sqliteStep, [.stmt2]
        cinvoke sqliteReset, [.stmt2]

        stdcall StrDel, edi

        jmp     .loop

.finish:
        cinvoke sqliteFinalize, [.stmt2]
        cinvoke sqliteFinalize, [.stmt]

        stdcall GetBackLink, esi
        push    eax

        stdcall StrMakeRedirect, 0, eax
        stdcall StrDel ; from the stack

        mov     [esp+4*regEAX], eax
        stc

        popad
        return
endp







; Print the envoronment and post data to STDERR. ONLY for debugging purposes, especially for POST requests.

Changes to source/showthread.asm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

sqlSelectPosts StripText "showthread.sql", SQL

sqlGetPostCount  text "select count(1) from Posts where ThreadID = ?"
sqlGetThreadInfo text "select id, caption, slug from Threads where slug = ? limit 1"



proc ShowThread, .pSpecial

.stmt  dd ?
.stmt2 dd ?

.threadID dd ?








<







1
2
3
4
5
6
7

8
9
10
11
12
13
14

sqlSelectPosts StripText "showthread.sql", SQL

sqlGetPostCount  text "select count(1) from Posts where ThreadID = ?"
sqlGetThreadInfo text "select id, caption, slug from Threads where slug = ? limit 1"



proc ShowThread, .pSpecial

.stmt  dd ?
.stmt2 dd ?

.threadID dd ?

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
        mov     [.cnt], 0

.loop:
        cinvoke sqliteStep, [.stmt]
        cmp     eax, SQLITE_ROW
        jne     .finish


        inc     [.cnt]

;if defined options.DebugMode & options.DebugMode
;        stdcall GetFineTimestamp
;        push    eax
;end if

        stdcall StrCatTemplate, edi, "post_view", [.stmt], esi

;if defined options.DebugMode & options.DebugMode
;        stdcall GetFineTimestamp
;        sub     eax, [esp]
;
;        OutputValue "Template: ", eax, 10, -1
;        pop     eax
;end if


        cinvoke sqliteColumnInt, [.stmt], 0
        stdcall PostIncrementReadCount, eax

        mov     ebx, [esi+TSpecialParams.userID]
        test    ebx, ebx
        jz      .loop

        stdcall SetPostRead, ebx, eax

        jmp     .loop


.finish:

;if defined options.DebugMode & options.DebugMode
;        stdcall GetFineTimestamp
;        sub     eax, [.start]
;
;        OutputValue "Thread fetch query time [us]: ", eax, 10, -1
;end if

        cmp     [.cnt], 5
        jbe     .back_navigation_ok

        stdcall StrCat, edi, [.list]
        stdcall StrCatTemplate, edi, "nav_thread", [.stmt2], esi

.back_navigation_ok:







<


<
<
<
<
<

<
<
<
<
<
<
<
<
<















<
<
<
<
<
<
<







101
102
103
104
105
106
107

108
109





110









111
112
113
114
115
116
117
118
119
120
121
122
123
124
125







126
127
128
129
130
131
132
        mov     [.cnt], 0

.loop:
        cinvoke sqliteStep, [.stmt]
        cmp     eax, SQLITE_ROW
        jne     .finish


        inc     [.cnt]






        stdcall StrCatTemplate, edi, "post_view", [.stmt], esi










        cinvoke sqliteColumnInt, [.stmt], 0
        stdcall PostIncrementReadCount, eax

        mov     ebx, [esi+TSpecialParams.userID]
        test    ebx, ebx
        jz      .loop

        stdcall SetPostRead, ebx, eax

        jmp     .loop


.finish:








        cmp     [.cnt], 5
        jbe     .back_navigation_ok

        stdcall StrCat, edi, [.list]
        stdcall StrCatTemplate, edi, "nav_thread", [.stmt2], esi

.back_navigation_ok:

Changes to source/showthread.sql.

1
2
3
4
5
6
7
8
9
10
11
12
13
select

  P.id,
  P.threadID,
  strftime('%d.%m.%Y %H:%M:%S', P.postTime, 'unixepoch') as PostTime,
  P.Content,
  U.id as UserID,
  U.nick as UserName,
  U.PostCount as UserPostCount,
  U.av_time as AVer,
  ?4 as Slug,
  (select count() from UnreadPosts UP where UP.UserID = ?5 and UP.PostID = P.id) as Unread,
  P.ReadCount





|







1
2
3
4
5
6
7
8
9
10
11
12
13
select

  P.id,
  P.threadID,
  strftime('%d.%m.%Y %H:%M:%S', P.postTime, 'unixepoch') as PostTime,
  P.Rendered,
  U.id as UserID,
  U.nick as UserName,
  U.PostCount as UserPostCount,
  U.av_time as AVer,
  ?4 as Slug,
  (select count() from UnreadPosts UP where UP.UserID = ?5 and UP.PostID = P.id) as Unread,
  P.ReadCount

Changes to www/.htaccess.



1

2


FcgidWrapper "/FULL/PATH/TO/engine" virtual

SetHandler fcgid-script
>
>
|
>

1
2
3
4
5
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

FcgidWrapper "/home/asm32inf/board/engine" virtual
SetHandler fcgid-script

Changes to www/templates/post_view.tpl.

12
13
14
15
16
17
18
19
20
21
    <div class="edit_tools">
      [case:[special:canpost]| |<a class="quote_btn" href="[id]/!post"><img class="quote_icon" src="/images/quote.svg" alt="Quote | "></a>]
      [case:[special:canedit]| |<a class="edit_btn" href="[id]/!edit"><img class="edit_icon" src="/images/edit_gray.svg" alt="Edit | "></a>]
      [case:[special:candel] | |<a class="del_btn" href="[id]/!confirm"><img class="del_icon" src="/images/del_gray.svg" alt="Delete"></a>]
    </div>
  </div>
  <div class="post_text">
    [minimag:[content]]
  </div>
</div>







|


12
13
14
15
16
17
18
19
20
21
    <div class="edit_tools">
      [case:[special:canpost]| |<a class="quote_btn" href="[id]/!post"><img class="quote_icon" src="/images/quote.svg" alt="Quote | "></a>]
      [case:[special:canedit]| |<a class="edit_btn" href="[id]/!edit"><img class="edit_icon" src="/images/edit_gray.svg" alt="Edit | "></a>]
      [case:[special:candel] | |<a class="del_btn" href="[id]/!confirm"><img class="del_icon" src="/images/del_gray.svg" alt="Delete"></a>]
    </div>
  </div>
  <div class="post_text">
    [html:[rendered]]
  </div>
</div>