Browse Source

Add (but don't use) Twig templates from OPS

biotorrents 4 years ago
parent
commit
79fde763fc
100 changed files with 5106 additions and 54 deletions
  1. 471
    0
      templates/admin/advanced-user-search.twig
  2. 20
    0
      templates/admin/announcekey-history.twig
  3. 23
    0
      templates/admin/bonus-points.twig
  4. 134
    0
      templates/admin/bonus-stats.twig
  5. 325
    0
      templates/admin/cache-db-stats.twig
  6. 100
    0
      templates/admin/cache-management.twig
  7. 51
    0
      templates/admin/changelog.twig
  8. 53
    0
      templates/admin/client-whitelist.twig
  9. 42
    0
      templates/admin/db-table.twig
  10. 26
    0
      templates/admin/duplicate-ipaddr.twig
  11. 79
    0
      templates/admin/history-ip-tracker.twig
  12. 116
    0
      templates/admin/login-watch.twig
  13. 229
    0
      templates/admin/notification-sandbox.twig
  14. 179
    0
      templates/admin/privilege-list.twig
  15. 30
    0
      templates/admin/privilege-matrix.twig
  16. 48
    0
      templates/admin/ratio-watch.twig
  17. 135
    0
      templates/admin/registration.twig
  18. 48
    0
      templates/admin/site-info-userrank.twig
  19. 111
    0
      templates/admin/site-info.twig
  20. 57
    0
      templates/admin/site-option.twig
  21. 27
    0
      templates/admin/staffpm-list.twig
  22. 50
    0
      templates/admin/tracker-info.twig
  23. 27
    0
      templates/admin/user-custom-permission.twig
  24. 16
    0
      templates/admin/user-info-email.twig
  25. 16
    0
      templates/admin/user-info-ipv4.twig
  26. 33
    0
      templates/admin/userflow.twig
  27. 86
    0
      templates/applicant/admin.twig
  28. 76
    0
      templates/applicant/apply.twig
  29. 136
    0
      templates/applicant/view.twig
  30. 39
    0
      templates/artist/similar.twig
  31. 5
    0
      templates/better/links.twig
  32. 69
    0
      templates/better/missing.twig
  33. 16
    0
      templates/better/single.twig
  34. 20
    0
      templates/better/torrents.twig
  35. 4
    0
      templates/better/zip.twig
  36. 31
    0
      templates/bonus/bonus-pool.twig
  37. 43
    0
      templates/bonus/store.twig
  38. 8
    0
      templates/bonus/token-other.twig
  39. 13
    0
      templates/bookmark/body.twig
  40. 13
    0
      templates/bookmark/footer.twig
  41. 35
    0
      templates/bookmark/header.twig
  42. 8
    0
      templates/bookmark/none.twig
  43. 26
    0
      templates/collage/delete.twig
  44. 46
    0
      templates/collage/description.twig
  45. 30
    0
      templates/collage/header.twig
  46. 24
    0
      templates/collage/recover.twig
  47. 131
    0
      templates/collage/sidebar.twig
  48. 27
    0
      templates/collector.twig
  49. 57
    0
      templates/comment/comment.twig
  50. 45
    0
      templates/comment/warn.twig
  51. 137
    0
      templates/contest/admin-form.twig
  52. 16
    0
      templates/contest/intro.twig
  53. 34
    0
      templates/contest/leaderboard.twig
  54. 25
    0
      templates/contest/list.twig
  55. 17
    0
      templates/contest/payout-uploader.twig
  56. 11
    0
      templates/contest/switcher.twig
  57. 24
    0
      templates/debug/cache.twig
  58. 40
    0
      templates/debug/class.twig
  59. 25
    0
      templates/debug/error.twig
  60. 16
    0
      templates/debug/extension.twig
  61. 30
    0
      templates/debug/flag.twig
  62. 13
    0
      templates/debug/include.twig
  63. 27
    0
      templates/debug/ocelot.twig
  64. 14
    0
      templates/debug/performance.twig
  65. 31
    0
      templates/debug/query.twig
  66. 20
    0
      templates/debug/sphinxql.twig
  67. 27
    0
      templates/debug/task.twig
  68. 24
    0
      templates/debug/var.twig
  69. 69
    0
      templates/donation/admin-panel.twig
  70. 13
    0
      templates/donation/donation-pm.twig
  71. 55
    0
      templates/donation/history.twig
  72. 57
    0
      templates/donation/reward-list.twig
  73. 111
    0
      templates/donation/special-rank-1.twig
  74. 8
    0
      templates/donation/special-rank-2.twig
  75. 6
    0
      templates/donation/special-rank-3.twig
  76. 20
    0
      templates/donation/stats.twig
  77. 12
    0
      templates/email/disable-warning.twig
  78. 8
    0
      templates/email/enable_request_accepted.twig
  79. 9
    0
      templates/email/enable_request_denied.twig
  80. 14
    0
      templates/email/hacked.twig
  81. 23
    0
      templates/email/invite-interviewer.twig
  82. 29
    0
      templates/email/invite-member.twig
  83. 11
    0
      templates/email/password_reset.twig
  84. 31
    0
      templates/email/recovery.twig
  85. 22
    0
      templates/email/referral.twig
  86. 9
    0
      templates/email/registration.twig
  87. 4
    4
      templates/enable_request_accepted.tpl
  88. 6
    4
      templates/enable_request_denied.tpl
  89. 46
    46
      templates/error.tpl
  90. 48
    0
      templates/error.twig
  91. 69
    0
      templates/forum/header-thread.twig
  92. 53
    0
      templates/forum/header.twig
  93. 40
    0
      templates/forum/main.twig
  94. 106
    0
      templates/forum/new-thread.twig
  95. 3
    0
      templates/forum/request-edit.twig
  96. 20
    0
      templates/forum/toc.twig
  97. 48
    0
      templates/forum/warn.twig
  98. 23
    0
      templates/inbox/compose.twig
  99. 168
    0
      templates/index/private-header.twig
  100. 0
    0
      templates/index/private-main.twig

+ 471
- 0
templates/admin/advanced-user-search.twig View File

@@ -0,0 +1,471 @@
1
+{% from 'macro/form.twig' import checked, selected %}
2
+
3
+<div class="thin">
4
+<form class="search_form" name="users" action="user.php" method="get">
5
+<input type="hidden" name="action" value="search" />
6
+
7
+<table class="layout"><tr>
8
+    <td style="vertical-align:top;"><table class="layout">
9
+        <tr>
10
+        <td class="label nobr">Username:</td>
11
+        <td>
12
+            <input type="text" name="username" size="20" value="{{ username }}" />
13
+        </td>
14
+        </tr>
15
+
16
+        <tr>
17
+        <td class="label nobr">Email address:</td>
18
+        <td>
19
+            <input type="text" name="email" size="20" value="{{ email }}" />
20
+        </td>
21
+        </tr>
22
+
23
+        <tr>
24
+        <td class="label tooltip nobr" title="To fuzzy search (default) for a block of addresses
25
+            (e.g. 55.66.77.*), enter &quot;55.66.77.&quot; withou'] ?? '')?>t the quotes">Site IP:</td>
26
+        <td>
27
+            <input type="text" name="ip" size="20" value="{{ ip }}" />
28
+        </td>
29
+        </tr>
30
+
31
+        <tr>
32
+        <td class="label nobr">Tracker IP:<br />
33
+          <div style="padding-left: 20px; text-align: left;">
34
+            <input type="radio" name="tracker-src" id="tracker-src-live" value="live"{{ checked(tracker_live_source) }} />
35
+            <label class="tooltip" for="tracker-src" title="Search for client ip addresses currently connecting to the tracker" for="tracker-src-live">Live</label><br />
36
+            <input type="radio" name="tracker-src" id="tracker-src-hist" value="hist"{{ checked(not tracker_live_source) }} />
37
+            <label class="tooltip" for="tracker-src" title="Search for ip addresses that have been seen by the tracker (but may be not connected at this time)" for="tracker-src-hist">Historical</label>
38
+          </div>
39
+        </td>
40
+        <td>
41
+            <input type="text" name="tracker_ip" size="20" value="{{ tracker_ip }}" />
42
+        </td>
43
+        </tr>
44
+
45
+        <tr>
46
+        <td class="label nobr">Staff notes:</td>
47
+        <td>
48
+            <input type="text" name="comment" size="20" value="{{ comment }}" />
49
+        </td>
50
+        </tr>
51
+
52
+        <tr>
53
+        <td class="label nobr">Passkey:</td>
54
+        <td>
55
+            <input type="text" name="passkey" size="20" value="{{ passkey }}" />
56
+        </td>
57
+        </tr>
58
+
59
+        <tr>
60
+        <td class="label tooltip nobr" title="Supports partial URL matching, e.g. entering
61
+            &quot;&#124;https://ptpimg.me&quot; will search for avatars hosted on https://phpimg.me">Avatar URL:</td>
62
+        <td>
63
+            <input type="text" name="avatar" size="20" value="{{ avatar }}" />
64
+        </td>
65
+        </tr>
66
+
67
+        <tr>
68
+        <td class="label nobr">Last.fm username:</td>
69
+        <td>
70
+            <input type="text" name="lastfm" size="20" value="{{ lastfm }}" />
71
+        </td>
72
+        </tr>
73
+
74
+        <tr>
75
+        <td class="nobr" colspan="2">
76
+        <h4>Extra</h4>
77
+        <ul class="options_list nobullet">
78
+            <li title="Only display users that have a disabled account linked by IP address">
79
+                <input type="checkbox" name="disabled_ip" id="disabled_ip"{{ checked(check_disabled_ip) }} />
80
+                <label for="disabled_ip">Disabled accounts linked by IP</label>
81
+            </li>
82
+            <li>
83
+                <input type="checkbox" name="ip_history" id="ip_history"{{ checked(check_ip_history) }} />
84
+                <label title="Disabled accounts linked by IP must also be checked" for="ip_history">IP history</label>
85
+            </li>
86
+            <li>
87
+                <input type="checkbox" name="email_history" id="email_history"{{ checked(check_email_history) }} />
88
+                <label title="Also search the email addresses the member used in the past" for="email_history">Email history</label>
89
+            </li>
90
+        </ul>
91
+        </tr>
92
+    </table></td>
93
+
94
+{# new column #}
95
+
96
+    <td style="vertical-align:top;"><table class="layout">
97
+        <tr>
98
+        <td class="label nobr">Joined:</td>
99
+        <td style="white-space: nowrap;">
100
+            <select name="joined">
101
+                <option value="on"{{ selected(joined_op == 'on') }}>On</option>
102
+                <option value="before"{{ selected(joined_op == 'before') }}>Before</option>
103
+                <option value="after"{{ selected(joined_op == 'after') }}>After</option>
104
+                <option value="between"{{ selected(joined_op == 'between') }}>Between</option>
105
+            </select>
106
+            <input type="text" name="join1" size="10" value="{{ joined_min }}" placeholder="YYYY-MM-DD" />
107
+            <input type="text" name="join2" size="10" value="{{ joined_max }}" placeholder="YYYY-MM-DD" />
108
+        </td>
109
+        </tr>
110
+
111
+        <tr>
112
+        <td class="label nobr">Last active:</td>
113
+        <td style="white-space: nowrap;">
114
+            <select name="lastactive">
115
+                <option value="on"{{ selected(last_active_op == 'on') }}>On</option>
116
+                <option value="before"{{ selected(last_active_op == 'before') }}>Before</option>
117
+                <option value="after"{{ selected(last_active_op == 'after') }}>After</option>
118
+                <option value="between"{{ selected(last_active_op == 'between') }}>Between</option>
119
+            </select>
120
+            <input type="text" name="lastactive1" size="10" value="{{ last_active_min }}" placeholder="YYYY-MM-DD" />
121
+            <input type="text" name="lastactive2" size="10" value="{{ last_active_max }}" placeholder="YYYY-MM-DD" />
122
+        </td>
123
+        </tr>
124
+
125
+        <tr>
126
+        <td class="label nobr" title="The number of releases downloaded (may be greater than snatched">Downloads:</td>
127
+        <td width="30%">
128
+            <select name="downloads">
129
+                <option value="off"{{ selected(downloads_op == 'off') }}>Off</option>
130
+                <option value="equal"{{ selected(downloads_op == 'equal') }}>Equal</option>
131
+                <option value="above"{{ selected(downloads_op == 'above') }}>Above</option>
132
+                <option value="below"{{ selected(downloads_op == 'below') }}>Below</option>
133
+                <option value="between"{{ selected(downloads_op == 'between') }}>Between</option>
134
+            </select>
135
+            <input type="text" name="downloads1" size="6" value="{{ downloads_min }}" />
136
+            <input type="text" name="downloads2" size="6" value="{{ downloads_max }}" />
137
+        </td>
138
+        </tr>
139
+
140
+        <tr>
141
+        <td class="label nobr">Snatched:</td>
142
+        <td width="30%">
143
+            <select name="snatched">
144
+                <option value="off"{{ selected(snatched_op == 'off') }}>Off</option>
145
+                <option value="equal"{{ selected(snatched_op == 'equal') }}>Equal</option>
146
+                <option value="above"{{ selected(snatched_op == 'above') }}>Above</option>
147
+                <option value="below"{{ selected(snatched_op == 'below') }}>Below</option>
148
+                <option value="between"{{ selected(snatched_op == 'between') }}>Between</option>
149
+            </select>
150
+            <input type="text" name="snatched1" size="6" value="{{ snatched_min }}" />
151
+            <input type="text" name="snatched2" size="6" value="{{ snatched_max }}" />
152
+        </td>
153
+        </tr>
154
+
155
+        <tr>
156
+        <td class="label nobr">Seeding:</td>
157
+        <td width="30%">
158
+            <select name="seeding">
159
+                <option value="off"{{ selected(seeding_op == 'off') }}>Off</option>
160
+                <option value="equal"{{ selected(seeding_op == 'equal') }}>Equal</option>
161
+                <option value="above"{{ selected(seeding_op == 'above') }}>Above</option>
162
+                <option value="below"{{ selected(seeding_op == 'below') }}>Below</option>
163
+                <option value="between"{{ selected(seeding_op == 'between') }}>Between</option>
164
+            </select>
165
+            <input type="text" name="seeding1" size="6" value="{{ seeding_min }}" />
166
+            <input type="text" name="seeding2" size="6" value="{{ seeding_max }}" />
167
+        </td>
168
+        </tr>
169
+
170
+        <tr>
171
+        <td class="label tooltip nobr" title="Units are GiB">Data Uploaded:</td>
172
+        <td width="30%">
173
+            <select name="uploaded">
174
+                <option value="equal"{{ selected(downloaded_op == 'equal') }}>Equal</option>
175
+                <option value="above"{{ selected(downloaded_op == 'above') }}>Above</option>
176
+                <option value="below"{{ selected(downloaded_op == 'below') }}>Below</option>
177
+                <option value="between"{{ selected(downloaded_op == 'between') }}>Between</option>
178
+                <option value="buffer"{{ selected(downloaded_op == 'buffer') }}>buffer</option>
179
+            </select>
180
+            <input type="text" name="uploaded1" size="6" value="{{ uploaded_min }}" />
181
+            <input type="text" name="uploaded2" size="6" value="{{ uploaded_max }}" />
182
+        </td>
183
+        </tr>
184
+
185
+        <tr>
186
+        <td class="label tooltip nobr" title="Units are GiB">Data Downloaded:</td>
187
+        <td width="30%">
188
+            <select name="downloaded">
189
+                <option value="equal"{{ selected(downloaded_op == 'equal') }}>Equal</option>
190
+                <option value="above"{{ selected(downloaded_op == 'above') }}>Above</option>
191
+                <option value="below"{{ selected(downloaded_op == 'below') }}>Below</option>
192
+                <option value="between"{{ selected(downloaded_op == 'between') }}>Between</option>
193
+            </select>
194
+            <input type="text" name="downloaded1" size="6" value="{{ downloaded_min }}" />
195
+            <input type="text" name="downloaded2" size="6" value="{{ downloaded_max }}" />
196
+        </td>
197
+        </tr>
198
+
199
+        <tr>
200
+        <td class="label tooltip nobr" title="Units are GiB">Request Bounty:</td>
201
+        <td width="30%">
202
+            <select name="bounty">
203
+                <option value="equal"{{ selected(bounty_op == 'equal') }}>Equal</option>
204
+                <option value="above"{{ selected(bounty_op == 'above') }}>Above</option>
205
+                <option value="below"{{ selected(bounty_op == 'below') }}>Below</option>
206
+                <option value="between"{{ selected(bounty_op == 'between') }}>Between</option>
207
+            </select>
208
+            <input type="text" name="bounty1" size="6" value="{{ bounty_min }}" />
209
+            <input type="text" name="bounty2" size="6" value="{{ bounty_max }}" />
210
+        </td>
211
+        </tr>
212
+
213
+        <tr>
214
+        <td class="label nobr">Ratio:</td>
215
+        <td width="30%">
216
+            <select name="ratio">
217
+                <option value="equal"{{ selected(ratio_op == 'equal') }}>Equal</option>
218
+                <option value="above"{{ selected(ratio_op == 'above') }}>Above</option>
219
+                <option value="below"{{ selected(ratio_op == 'below') }}>Below</option>
220
+                <option value="between"{{ selected(ratio_op == 'between') }}>Between</option>
221
+            </select>
222
+            <input type="text" name="ratio1" size="6" value="{{ ratio_min }}" />
223
+            <input type="text" name="ratio2" size="6" value="{{ ratio_max }}" />
224
+        </td>
225
+        </tr>
226
+
227
+        <tr>
228
+        <td class="label nobr"># of invites:</td>
229
+        <td>
230
+            <select name="invites">
231
+                <option value="equal"{{ selected(invites_op == 'equal') }}>Equal</option>
232
+                <option value="above"{{ selected(invites_op == 'above') }}>Above</option>
233
+                <option value="below"{{ selected(invites_op == 'below') }}>Below</option>
234
+                <option value="between"{{ selected(invites_op == 'between') }}>Between</option>
235
+            </select>
236
+            <input type="text" name="invites1" size="6" value="{{ invites_min }}" />
237
+            <input type="text" name="invites2" size="6" value="{{ invites_max }}" />
238
+        </td>
239
+        </tr>
240
+
241
+        <tr>
242
+        <td width="30%" class="label nobr"># invited:</td>
243
+        <td>
244
+            <select name="invited">
245
+                <option value="off"{{ selected(invited_op == 'off') }}>Off</option>
246
+                <option value="equal"{{ selected(invited_op == 'equal') }}>Equal</option>
247
+                <option value="above"{{ selected(invited_op == 'above') }}>Above</option>
248
+                <option value="below"{{ selected(invited_op == 'below') }}>Below</option>
249
+                <option value="between"{{ selected(invited_op == 'between') }}>Between</option>
250
+            </select>
251
+            <input type="text" name="invited1" size="6" value="{{ invited_min }}" />
252
+            <input type="text" name="invited2" size="6" value="{{ invited_max }}" />
253
+        </td>
254
+        </tr>
255
+
256
+        <tr>
257
+        <td class="label nobr"># of emails:</td>
258
+        <td>
259
+            <select name="emails_opt">
260
+                <option value="equal"{{ selected(email_op == 'any') }}>Equal</option>
261
+                <option value="above"{{ selected(email_op == 'locked') }}>Above</option>
262
+                <option value="below"{{ selected(email_op == 'unlocked') }}>Below</option>
263
+            </select>
264
+            <input type="text" name="email_cnt" size="6" value="{{ email_value }}" />
265
+        </td>
266
+        </tr>
267
+    </table></td>
268
+
269
+{# new column #}
270
+
271
+    <td style="vertical-align:top;"><table class="layout">
272
+        <tr>
273
+        <td class="label nobr">Primary class:</td>
274
+        <td>
275
+            <select name="class[]" size="3" multiple="multiple">
276
+{% for c in primary_class %}
277
+                <option value="{{ c.ID }}"{{ selected(c.ID in primary_current) }}>{{ c.Name|shorten(12) }} ({{ c.Level }})</option>
278
+{% endfor %}
279
+            </select>
280
+        </td>
281
+        </tr>
282
+
283
+        <tr>
284
+        <td class="label nobr">Secondary class:</td>
285
+        <td>
286
+            <select name="secclass">
287
+                <option value=""{{ selected(sec_current == '') }}>Don't Care</option>
288
+{% for c in secondary_class %}
289
+                <option value="{{ c.ID }}"{{ selected(sec_current == c.ID) }}>{{ c.Name|shorten(20) }}</option>
290
+{% endfor %}
291
+            </select>
292
+        </td>
293
+        </tr>
294
+
295
+        <tr>
296
+        <td class="label nobr">Enabled:</td>
297
+        <td>
298
+            <select name="enabled">
299
+                <option value=""{{ selected(enabled == '') }}>Don't Care</option>
300
+                <option value="0"{{ selected(enabled == '0') }}>Unconfirmed</option>
301
+                <option value="1"{{ selected(enabled == '1') }}>Enabled</option>
302
+                <option value="2"{{ selected(enabled == '2') }}>Disabled</option>
303
+            </select>
304
+        </td>
305
+        </tr>
306
+
307
+        <tr>
308
+        <td class="label nobr">Donor:</td>
309
+        <td>
310
+            <select name="donor">
311
+                <option value=""{{ selected(donor == '') }}>Don't Care</option>
312
+                <option value="yes"{{ selected(donor == 'yes') }}>Yes</option>
313
+                <option value="no"{{ selected(donor == 'no') }}>No</option>
314
+            </select>
315
+        </td>
316
+        </tr>
317
+
318
+        <tr>
319
+        <td class="label nobr">Warned:</td>
320
+        <td>
321
+            <select name="warned">
322
+                <option value=""{{ selected(warned == '') }}>Don't Care</option>
323
+                <option value="isnotnull"{{ selected(warned == 'isnotnull') }}>Yes</option>
324
+                <option value="isnull"{{ selected(warned == 'isnull') }}>No</option>
325
+            </select>
326
+        </td>
327
+        </tr>
328
+
329
+        <tr>
330
+        <td class="label nobr">Locked Account:</td>
331
+        <td>
332
+            <select name="lockedaccount">
333
+                <option value="any"{{ selected(locked_account == 'any') }}>Don't Care</option>
334
+                <option value="locked"{{ selected(locked_account == 'locked') }}>Locked</option>
335
+                <option value="unlocked"{{ selected(locked_account == 'unlocked') }}>Unlocked</option>
336
+            </select>
337
+        </td>
338
+        </tr>
339
+
340
+        <tr>
341
+        <td class="label nobr">Disabled invites:</td>
342
+        <td>
343
+            <select name="disabled_invites">
344
+                <option value=""{{ selected(disabled_invites == '') }}>Don't Care</option>
345
+                <option value="yes"{{ selected(disabled_invites == 'yes') }}>Yes</option>
346
+                <option value="no"{{ selected(disabled_invites == 'no') }}>No</option>
347
+            </select>
348
+        </td>
349
+        </tr>
350
+
351
+        <tr>
352
+        <td class="label nobr">Disabled uploads:</td>
353
+        <td>
354
+            <select name="disabled_uploads">
355
+                <option value=""{{ selected(disabled_uploads == '') }}>Don't Care</option>
356
+                <option value="yes"{{ selected(disabled_uploads == 'yes') }}>Yes</option>
357
+                <option value="no"{{ selected(disabled_uploads == 'no') }}>No</option>
358
+            </select>
359
+        </td>
360
+        </tr>
361
+
362
+        <tr>
363
+        <td class="label nobr">Stylesheet:</td>
364
+        <td>
365
+            <select name="stylesheet" id="stylesheet">
366
+                <option value="">Don't Care</option>
367
+{% for s in stylesheet %}
368
+                <option value="{{ s.ID }} "{{ selected(style_current == s.ID) }}>{{ s.ProperName }}</option>
369
+{% endfor %}
370
+            </select>
371
+        </td>
372
+        </tr>
373
+
374
+        <tr>
375
+        <td class="label tooltip nobr" title="Two-letter codes as defined in ISO 3166-1 alpha-2">Country code:</td>
376
+        <td width="30%">
377
+            <select name="cc_op">
378
+                <option value="equal"{{ selected(ccode_op == 'equal') }}>Equals</option>
379
+                <option value="not_equal"{{ selected(ccode_op == 'not_equal') }}>Not equal</option>
380
+            </select>
381
+            <input type="text" name="cc" size="2" value="{{ ccode }}" />
382
+        </td>
383
+        </tr>
384
+
385
+        <tr>
386
+        <td class="label nobr">Search type:</td>
387
+        <td>
388
+            <ul class="options_list nobullet">
389
+                <li>
390
+                    <input type="radio" name="matchtype" id="strict_match_type" value="strict"{{ checked(match_mode == 'strict') }} />
391
+                    <label class="tooltip" title="A &quot;strict&quot; search uses no wildcards in search fields,
392
+                        and it is analogous to &#96;grep -E &quot;&circ;SEARCHTERM&#36;&quot;&#96;" for="strict_match_type">Strict</label>
393
+                </li>
394
+                <li>
395
+                    <input type="radio" name="matchtype" id="fuzzy_match_type" value="fuzzy"{{ checked(match_mode == 'fuzzy') }} />
396
+                    <label class="tooltip" title="A &quot;fuzzy&quot; search automatically prepends and appends wildcards to
397
+                        search strings, except for IP address searches, unless the search string begins or ends with a
398
+                        &quot;&#124;&quot; (pipe). It is analogous to a vanilla grep search (except for the pipe stuff)." for="fuzzy_match_type">Fuzzy</label>
399
+                </li>
400
+                <li>
401
+                    <input type="radio" name="matchtype" id="regexp_match_type" value="regexp"{{ checked(match_mode == 'regexp') }} />
402
+                    <label class="tooltip" title="A &quot;regexp&quot; search uses MySQL's regular expression syntax." for="regexp_match_type">Regexp</label>
403
+                </li>
404
+            </ul>
405
+        </td>
406
+        </tr>
407
+    </table></td>
408
+</tr>
409
+</table>
410
+
411
+{# end last column #}
412
+
413
+Results ordered <select name="order">
414
+{% for field in field_by %}
415
+    <option value="{{ field }}"{{ selected(field == field_current)}}>{{ field }}</option>
416
+{% endfor %}
417
+</select>
418
+
419
+<select name="way">
420
+{% for dir in order_by %}
421
+    <option value="{{ dir }}"{{ selected(dir == order_current) }}>{{ dir }}</option>
422
+{% endfor %}
423
+</select>
424
+<input type="submit" value=" Search " />
425
+
426
+</form>
427
+</div>
428
+
429
+{{ paginator.linkbox|raw }}
430
+<div class="box pad center">
431
+    <h2>{{ total|number_format }} result{{ total|plural }}</h2>
432
+    <table width="100%">
433
+        <tr class="colhead">
434
+            <td>Username</td>
435
+            <td>Email</td>
436
+            <td>Joined</td>
437
+            <td>Last seen</td>
438
+            <td>Upload</td>
439
+            <td>Download</td>
440
+            <td>Ratio</td>
441
+            <td>Bounty</td>
442
+            <td>Downloads</td>
443
+            <td>Snatched</td>
444
+            <td>Seeding</td>
445
+            <td>Invites</td>
446
+{% if show_invited %}
447
+            <td>Invited</td>
448
+{% endif %}
449
+        </tr>
450
+{% for u in page %}
451
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
452
+            <td>{{ u.user_id|user_full }}</td>
453
+            <td>{{ u.email }}</td>
454
+            <td>{{ u.join_date|time_diff }}</td>
455
+            <td>{{ u.last_access|time_diff }}</td>
456
+            <td>{{ u.uploaded|octet_size }}</td>
457
+            <td>{{ u.downloaded|octet_size }}</td>
458
+            <td>{{ ratio(u.uploaded, u.downloaded) }}</td>
459
+            <td>{{ u.bounty|octet_size }}</td>
460
+            <td>{{ u.downloads|number_format }}</td>
461
+            <td>{% if u.snatches is numeric %}{{ u.snatches|number_format }}{% else %}{{ u.snatches }}{% endif %}</td>
462
+            <td>{% if u.seeding is numeric %}{{ u.seeding|number_format }}{% else %}{{ u.seeding }}{% endif %}</td>
463
+            <td>{{ u.invites|number_format }}{% if u.disable_invites %}<span title="Invites are disabled">&nbsp;&nbsp;&#x1F6AB;</span>{% endif %}</td>
464
+    {% if show_invited %}
465
+            <td>{{ u.invited|number_format }}</td>
466
+    {% endif %}
467
+        </tr>
468
+{% endfor %}
469
+    </table>
470
+</div>
471
+{{  paginator.linkbox|raw }}

+ 20
- 0
templates/admin/announcekey-history.twig View File

@@ -0,0 +1,20 @@
1
+<div class="header">
2
+    <h2><a href="/user.php?id={{ user.id }}">{{ user.username }}</a> &rsaquo; Announce Key History</h2>
3
+</div>
4
+<table width="100%">
5
+    <tr class="colhead">
6
+        <td>Old</td>
7
+        <td>New</td>
8
+        <td>Changed</td>
9
+        <td>IP <a href="/userhistory.php?action=ips&amp;userid={{ user.id }}" class="brackets">H</a></td>
10
+    </tr>
11
+{% for change in user.announceKeyHistory %}
12
+    <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
13
+        <td>{{ change.old }}</td>
14
+        <td>{{ change.new }}</td>
15
+        <td>{{ change.date|time_diff }}</td>
16
+        <td>{{ change.ipaddr }} <a href="user.php?action=search&amp;ip_history=on&amp;ip={{
17
+            change.ipaddr }}" class="brackets tooltip" title="Search">S</a><br />{{ resolveIpv4(change.ipaddr) }}</td>
18
+    </tr>
19
+{% endfor %}
20
+</table>

+ 23
- 0
templates/admin/bonus-points.twig View File

@@ -0,0 +1,23 @@
1
+<div class="header">
2
+    <h2>Add bonus points to enabled users</h2>
3
+</div>
4
+<div class="box pad" style="margin-left: auto; margin-right: auto; max-width: 80%;">
5
+    {{ message|raw }}
6
+    <form class="add_form" name="bonus-points" action="" method="post">
7
+        <input type="date" name="since_date" value="{{ since }}" />
8
+        <label for="since_date">Cut-off date for consideration</label><br /><br />
9
+
10
+        <input type="number" id="active_points" name="active_points" min="0" size="6" style="text-align: right;" />&nbsp;
11
+        <label for="active_points"> Add points to all enabled users who have been active on or after the cut-off date.</label><br /><br />
12
+
13
+        <input type="number" id="upload_points" name="upload_points" min="0" size="6" style="text-align: right;" />&nbsp;
14
+        <label for="upload_points"> Add points for people who have made an upload on or after the cut-off date.</label><br /><br />
15
+
16
+        <input type="number" id="seed_points" name="seed_points" min="0" size="6" style="text-align: right;" />&nbsp;
17
+        <label for="seed_points"> Add points for people who have been seeding now.</label><br /><br />
18
+
19
+        <input type="hidden" name="action" value="bonus_points" />
20
+        <input type="hidden" name="auth" value="{{ auth }}" />
21
+        <input type="submit" name="add_points" value="Add bonus points" />
22
+    </form>
23
+</div>

+ 134
- 0
templates/admin/bonus-stats.twig View File

@@ -0,0 +1,134 @@
1
+{% macro user(list, index) %}
2
+    {% if list[index] is defined %}{{ list[index].user_id|user_url }}{% else %}&nbsp;{% endif %}
3
+{% endmacro %}
4
+
5
+{% macro total(list, index) %}
6
+    {% if list[index] is defined %}{{ list[index].total|number_format }}{% else %}&nbsp;{% endif %}
7
+{% endmacro %}
8
+
9
+{% macro accrual(d) %}
10
+    {% if d is defined %}{{ d.total|number_format }}{% else %}&mdash;{% endif %}
11
+{% endmacro %}
12
+
13
+{% macro delta(interval, n) %}
14
+    {% set p = n - 1 %}
15
+    {% if interval[n] is defined and interval[p] is defined %}{{ (interval[p].total - interval[n].total)|number_format }}
16
+    {% elseif interval[n] is defined %}{{  interval[n].total|number_format }}
17
+    {% elseif interval[p] is defined %}{{ -interval[p].total|number_format }}
18
+    {% else %}&mdash;{% endif %}
19
+{% endmacro %}
20
+
21
+{% set max = 6 %}
22
+<div class="pad box">
23
+    <h2>Accrual</h2>
24
+    <table>
25
+        <tr class="colhead">
26
+            <td>Interval</td>
27
+            <td>Current</td>
28
+{% for n in range(1, max) %}
29
+            <td>&Delta; n-{{ n }}</td>
30
+{% endfor %}
31
+        </tr>
32
+        <tr class="rowa">
33
+            <td>Day</td>
34
+            <td>{{ _self.accrual(day.0) }}</td>
35
+{% for n in range(1, max) %}
36
+            <td title="{{ day[n].total|number_format }}">{{ _self.delta(day, n) }}</td>
37
+{% endfor %}
38
+        </tr>
39
+        <tr class="rowb">
40
+            <td>Week</td>
41
+            <td>{{ _self.accrual(week.0) }}</td>
42
+{% for n in range(1, max) %}
43
+            <td title="{{ week[n].total|number_format }}">{{ _self.delta(week, n) }}</td>
44
+{% endfor %}
45
+        </tr>
46
+        <tr class="rowb">
47
+            <td>Month</td>
48
+            <td>{{ _self.accrual(month.0) }}</td>
49
+{% for n in range(1, max) %}
50
+            <td title="{{ month[n].total|number_format }}">{{ _self.delta(month, n) }}</td>
51
+{% endfor %}
52
+        </tr>
53
+    </table>
54
+</div>
55
+
56
+<div class="pad box">
57
+    <h2>Item Purchases</h2>
58
+    <table>
59
+        <tr class="colhead">
60
+            <td>Item</td>
61
+            <td>Last day</td>
62
+            <td>Last week</td>
63
+            <td>Last month</td>
64
+            <td>Last quarter</td>
65
+            <td>Last year</td>
66
+            <td>Total</td>
67
+        </tr>
68
+{% set item = bonus.itemPurchase %}
69
+{% set day = bonus.expenditureRange('DAY', 0, 1) %}
70
+{% set week = bonus.expenditureRange('WEEK', 0, 1) %}
71
+{% set month = bonus.expenditureRange('MONTH', 0, 1) %}
72
+{% set quarter = bonus.expenditureRange('WEEK', 0, 13) %}
73
+{% set year = bonus.expenditureRange('YEAR', 0, 1) %}
74
+{% for i in item %}
75
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
76
+            <td>{{ i.title }}</td>
77
+            <td>{{ day[i.id].total|number_format }}</td>
78
+            <td>{{ week[i.id].total|number_format }}</td>
79
+            <td>{{ month[i.id].total|number_format }}</td>
80
+            <td>{{ quarter[i.id].total|number_format }}</td>
81
+            <td>{{ year[i.id].total|number_format }}</td>
82
+            <td>{{ i.total|number_format }}</td>
83
+        </tr>
84
+{% endfor %}
85
+    </table>
86
+</div>
87
+
88
+<div class="pad box">
89
+    <h2>Top 10 Users</h2>
90
+    <table>
91
+        <tr class="colhead">
92
+            <td>&nbsp;</td>
93
+            <td style="text-align: center;" colspan="2">Hoarders</td>
94
+            <td style="text-align: center;" colspan="2">Spenders</td>
95
+            <td style="text-align: center;" colspan="2">Pool Contributors</td>
96
+            <td style="text-align: center;" colspan="2">Overall Spenders</td>
97
+            <td>&nbsp;</td>
98
+        </tr>
99
+        <tr class="colhead">
100
+            <td>&nbsp;</td>
101
+            <td style="text-align: right;">Points</td>
102
+            <td>User</td>
103
+            <td style="text-align: right;">Points</td>
104
+            <td>User</td>
105
+            <td style="text-align: right;">Points</td>
106
+            <td>User</td>
107
+            <td style="text-align: right;">Points</td>
108
+            <td>User</td>
109
+            <td>&nbsp;</td>
110
+        </tr>
111
+{% set limit = 10 %}
112
+{% set hoarders = bonus.topHoarders(limit) %}
113
+{% set spenders = bonus.topSpenders(limit) %}
114
+{% set poolers  = bonus.topPoolContributors(limit) %}
115
+{% set overall = bonus.topAggregateSpenders(limit) %}
116
+{% for i in range(0, limit - 1) %}
117
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
118
+            <td style="text-align: right">{{ i + 1 }}</td>
119
+            <td style="text-align: right">{{ _self.total(hoarders, i) }}</td>
120
+            <td>{{ _self.user(hoarders, i) }}</td>
121
+
122
+            <td style="text-align: right">{{ _self.total(spenders, i) }}</td>
123
+            <td>{{ _self.user(spenders, i) }}</td>
124
+
125
+            <td style="text-align: right">{{ _self.total(poolers, i) }}</td>
126
+            <td>{{ _self.user(poolers, i) }}</td>
127
+
128
+            <td style="text-align: right">{{ _self.total(overall, i) }}</td>
129
+            <td>{{ _self.user(overall, i) }}</td>
130
+            <td style="text-align: right">{{ i + 1 }}</td>
131
+        </tr>
132
+{% endfor %}
133
+    </table>
134
+</div>

+ 325
- 0
templates/admin/cache-db-stats.twig View File

@@ -0,0 +1,325 @@
1
+{% if can_see_db %}
2
+<div class="linkbox">
3
+    <a href="tools.php?action=database_specifics" class="brackets">Database specifics</a>
4
+</div>
5
+{% endif %}
6
+<div class="permissions">
7
+    <div class="permission_container">
8
+        <table>
9
+            <tr class="colhead">
10
+                <td colspan="2">Service</td>
11
+            </tr>
12
+            <tr><td colspan="2"><strong>Threads (Active)</strong></td></tr>
13
+            <tr>
14
+                <td>Cache:</td>
15
+                <td>{{ mem_stats.threads|number_format }} <span style="float: right;">({{ (mem_stats.threads / mem_stats.max_connections)|number_format(1) }}%)</span></td>
16
+            </tr>
17
+            <tr>
18
+                <td{% if db_stats.Threads_connected.Value / db_stats.Threads_created.Value > 0.7 %} class="invalid"{% endif %}>Database:</td>
19
+                <td>{{ db_stats.Threads_created.Value|number_format }} <span style="float: right;">({{ (db_stats.Threads_connected.Value / db_stats.Threads_created.Value * 100)|number_format(1) }}%)</span></td>
20
+            </tr>
21
+            <tr>
22
+                <td>DB peak connections:</td>
23
+                <td>{{ db_stats.Max_used_connections.Value|number_format }} <span style="float: right;">({{ (db_stats.Max_used_connections.Value / db_vars.max_connections.Value)|number_format(1) }}%)</span></td>
24
+            </tr>
25
+            <tr><td colspan="2"></td></tr>
26
+            <tr><td colspan="2"><strong>Connections</strong></td></tr>
27
+            <tr>
28
+                <td>Cache current:</td>
29
+                <td>{{ mem_stats.curr_connections|number_format }}</td>
30
+            </tr>
31
+            <tr>
32
+                <td>Cache total:</td>
33
+                <td>{{ mem_stats.total_connections|number_format }}</td>
34
+            </tr>
35
+            <tr>
36
+                <td>Database total:</td>
37
+                <td>{{ db_stats.Connections.Value|number_format }}</td>
38
+            </tr>
39
+            <tr><td colspan="2"></td></tr>
40
+            <tr><td colspan="2"><strong>Booted</strong></td></tr>
41
+            <tr>
42
+                <td>Cache:</td>
43
+                <td>{{ (now - mem_stats.uptime)|time_diff }}</td>
44
+            </tr>
45
+            <tr>
46
+                <td>Database:</td>
47
+                <td>{{ (now - db_stats.Uptime.Value)|time_diff }}</td>
48
+            </tr>
49
+            <tr><td colspan="2"></td></tr>
50
+            <tr><td colspan="2"><strong>Special</strong></td></tr>
51
+            <tr>
52
+                <td>Cache Current Index:</td>
53
+                <td><span style="float: right;">{{ mem_stats.curr_items|number_format }}</span></td>
54
+            </tr>
55
+            <tr>
56
+                <td>Cache Total Index:</td>
57
+                <td><span style="float: right;">{{ mem_stats.total_items|number_format }}</span></td>
58
+            </tr>
59
+            <tr>
60
+                <td{% if mem_stats.bytes / mem_stats.limit_maxbytes > 0.85 %} class="tooltip invalid" title="Evictions begin when storage exceeds 85%"{% endif %}>Cache Storage:</td>
61
+                <td>{{ mem_stats.bytes|octet_size }} <span style="float: right;">{{ (mem_stats.bytes / mem_stats.limit_maxbytes)|number_format(5) }}%</span></td>
62
+            </tr>
63
+            <tr>
64
+                <td>Cache cold moves:</td>
65
+                <td>{{ mem_stats.moves_to_cold|number_format }}<span style="float: right;">{{ (mem_stats.moves_to_cold / mem_stats.uptime)|number_format(5) }}/s</span></td>
66
+            </tr>
67
+            <tr>
68
+                <td>Cache warm moves:</td>
69
+                <td>{{ mem_stats.moves_to_warm|number_format }}<span style="float: right;">{{ (mem_stats.moves_to_warm / mem_stats.uptime)|number_format(5) }}/s</span></td>
70
+            </tr>
71
+            <tr>
72
+                <td>Cache moves within LRU:</td>
73
+                <td>{{ mem_stats.moves_within_lru|number_format }}<span style="float: right;">{{ (mem_stats.moves_within_lru / mem_stats.uptime)|number_format(5) }}/s</span></td>
74
+            </tr>
75
+            <tr><td colspan="2"></td></tr>
76
+            <tr><td colspan="2"><strong>Utilities</strong></td></tr>
77
+            <tr>
78
+                <td>Cache:</td>
79
+                <td>
80
+                    <form class="delete_form" name="cache" action="" method="post">
81
+                        <input type="hidden" name="action" value="service_stats" />
82
+                        <input type="hidden" name="auth" value="{{ auth }}" />
83
+                        <input type="hidden" name="global_flush" value="1" />
84
+                        <input type="submit" value="Manual Flush" />
85
+                    </form>
86
+                </td>
87
+            </tr>
88
+            <tr>
89
+                <td{% if mem_stats.cmd_flush > mem_stats.uptime / 7 * 24 * 3600 -%}
90
+                    class="tooltip invalid" title="Flushing the cache on a regular basis defeats the benefits of it, look into using cache transactions, or deletes instead of global flushing where possible."
91
+                    {%- endif %}>Total flushes:</td>
92
+                <td>{{ mem_stats.cmd_flush|number_format }}</td>
93
+            </tr>
94
+            <tr>
95
+                <td>Flush ratio:</td>
96
+                <td>{{ (mem_stats.cmd_flush / mem_stats.uptime)|number_format(5) }}/s</td>
97
+            </tr>
98
+        </table>
99
+    </div>
100
+    <div class="permission_container">
101
+        <table>
102
+            <tr class="colhead">
103
+                <td colspan="2">Activity</td>
104
+            </tr>
105
+            <tr><td colspan="2"><strong>Total reads</strong></td></tr>
106
+            <tr>
107
+                <td>Cache:</td>
108
+                <td>{{ mem_stats.cmd_get|number_format }}</td>
109
+            </tr>
110
+            <tr>
111
+                <td>Database:</td>
112
+                <td>{{ db_stats.Com_select.Value|number_format }}</td>
113
+            </tr>
114
+            <tr><td colspan="2"><strong>Total writes</strong></td></tr>
115
+            <tr>
116
+                <td>Cache:</td>
117
+                <td>{{ mem_stats.cmd_set|number_format }}</td>
118
+            </tr>
119
+            <tr>
120
+                <td>Database:</td>
121
+                <td>{{ (db_stats.Com_insert.Value + db_stats.Com_update.Value)|number_format }}</td>
122
+            </tr>
123
+            <tr><td colspan="2"></td></tr>
124
+            <tr><td colspan="2"><strong>Get/Select (Success)</strong></td></tr>
125
+            <tr>
126
+                <td{% if mem_stats.get_hits / mem_stats.cmd_get < 0.7 %} class="invalid"{% endif %}>Cache:</td>
127
+                <td>{{ mem_stats.get_hits|number_format }} <span style="float: right;">({{ (mem_stats.get_hits / mem_stats.cmd_get * 100)|number_format(3) }}%)</span></td>
128
+            </tr>
129
+            <tr>
130
+                <td>Database:</td>
131
+                <td>{{ db_stats.Com_select.Value|number_format }} <span style="float: right;">(100.000%)</span></td>
132
+            </tr>
133
+            <tr><td colspan="2"><strong>Set/Insert (Success)</strong></td></tr>
134
+            <tr>
135
+                <td>Cache:</td>
136
+                <td>{{ mem_stats.cmd_set|number_format }} <span style="float: right;">(100.000%)</span></td>
137
+            </tr>
138
+            <tr>
139
+                <td>Database:</td>
140
+                <td>{{ db_stats.Com_insert.Value|number_format }} <span style="float: right;">(100.000%)</span></td>
141
+            </tr>
142
+            <tr>
143
+                <td{% if mem_stats.incr_hits/(mem_stats.incr_hits + mem_stats.incr_misses) < 0.7 %} class="invalid"{% endif %}>Cache increment:</td>
144
+                <td>{{ mem_stats.incr_hits|number_format }} <span style="float: right;">({{ (mem_stats.incr_hits / (mem_stats.incr_hits + mem_stats.incr_misses) * 100)|number_format(3) }}%)</span></td>
145
+            </tr>
146
+            <tr>
147
+                <td{% if mem_stats.decr_hits / (mem_stats.decr_hits + mem_stats.decr_misses) < 0.7 %} class="invalid"{% endif %}>Cache decrement:</td>
148
+                <td>{{ mem_stats.decr_hits|number_format }} <span style="float: right;">({{ (mem_stats.decr_hits / (mem_stats.decr_hits + mem_stats.decr_misses) * 100)|number_format(3) }}%)</span></td>
149
+            </tr>
150
+            <tr><td colspan="2"><strong>CAS/Update (Success)</strong></td></tr>
151
+            <tr>
152
+                <td{% if mem_stats.cas_hits > 0 and mem_stats.cas_hits / (mem_stats.cas_hits + mem_stats.cas_misses) < 0.7 -%} class="tooltip invalid" title="More than 30% of the issued CAS commands were unnecessarily wasting time and resources."
153
+                    {%- elseif mem_stats.cas_hits == 0 %} class="tooltip notice" title="Disable CAS with the -C parameter and save resources since it is not used."
154
+                    {%- endif %}>Cache:</td>
155
+                <td>{{ mem_stats.cas_hits|number_format }} <span style="float: right;">({%
156
+                    if mem_stats.cas_hits > 0 %}{{ mem_stats.cas_hits / ((mem_stats.cas_hits + mem_stats.cas_misses) * 100)|number_format(3) }}{% else %}0.000{% endif %}%)</span></td>
157
+            </tr>
158
+            <tr>
159
+                <td>Database:</td>
160
+                <td>{{ db_stats.Com_update.Value|number_format }} <span style="float: right;">(100.000%)</span></td>
161
+            </tr>
162
+            <tr><td colspan="2"><strong>Deletes (Success)</strong></td></tr>
163
+            <tr>
164
+                <td>Cache:</td>
165
+                <td>{{ mem_stats.delete_hits|number_format }} <span style="float: right;">({{ (mem_stats.delete_hits / (mem_stats.delete_hits + mem_stats.delete_misses) * 100)|number_format(3) }}%)</span></td>
166
+            </tr>
167
+            <tr>
168
+                <td>Database:</td>
169
+                <td>{{ db_stats.Com_delete.Value|number_format }} <span style="float: right;">(100.000%)</span></td>
170
+            </tr>
171
+            <tr><td colspan="2"></td></tr>
172
+            <tr><td colspan="2"><strong>Special</strong></td></tr>
173
+            <tr>
174
+                <td>Expired unfetched:</td>
175
+                <td>{{ mem_stats.expired_unfetched|number_format }}</td>
176
+            </tr>
177
+            <tr>
178
+                <td>Evicted unfetched:</td>
179
+                <td>{{ mem_stats.evicted_unfetched|number_format }}</td>
180
+            </tr>
181
+            <tr>
182
+                <td>Evicted:</td>
183
+                <td>{{ mem_stats.evictions|number_format }}</td>
184
+            </tr>
185
+            <tr>
186
+                <td>Slabs moved:</td>
187
+                <td>{{ mem_stats.slabs_moved|number_format }}</td>
188
+            </tr>
189
+            <tr>
190
+                <td{% if db_stats.Slow_queries.Value > db_stats.Questions.Value / 7500 %} class="tooltip invalid" title="1/7500 queries is allowed to be slow to minimize performance impact."{% endif %}>Database slow:</td>
191
+                <td>{{ db_stats.Slow_queries.Value|number_format }}</td>
192
+            </tr>
193
+            <tr><td colspan="2"></td></tr>
194
+            <tr><td colspan="2"><strong>Data read</strong></td></tr>
195
+            <tr>
196
+                <td>Cache:</td>
197
+                <td>{{ mem_stats.bytes_read|number_format }}</td>
198
+            </tr>
199
+            <tr>
200
+                <td>Database:</td>
201
+                <td>{{ db_stats.Bytes_received.Value|octet_size }}</td>
202
+            </tr>
203
+            <tr><td colspan="2"><strong>Data write</strong></td></tr>
204
+            <tr>
205
+                <td>Cache:</td>
206
+                <td>{{ mem_stats.bytes_written|octet_size }}</td>
207
+            </tr>
208
+            <tr>
209
+                <td>Database:</td>
210
+                <td>{{ db_stats.Bytes_sent.Value|octet_size }}</td>
211
+            </tr>
212
+        </table>
213
+    </div>
214
+    <div class="permission_container">
215
+        <table>
216
+            <tr class="colhead">
217
+                <td colspan="2">Concurrency</td>
218
+            </tr>
219
+            <tr><td colspan="2"><strong>Total reads</strong></td></tr>
220
+            <tr>
221
+                <td{% if mem_stats.cmd_get / mem_stats.uptime * 5 < db_stats.Com_select.Value / db_stats.Uptime.Value %} class="invalid"{% endif %}>Cache:</td>
222
+                <td>{{ (mem_stats.cmd_get / mem_stats.uptime)|number_format(5) }}/s</td>
223
+            </tr>
224
+            <tr>
225
+                <td>Database:</td>
226
+                <td>{{ (db_stats.Com_select.Value / db_stats.Uptime.Value)|number_format(5) }}/s</td>
227
+            </tr>
228
+            <tr><td colspan="2"><strong>Total writes</strong></td></tr>
229
+            <tr>
230
+                <td{% if mem_stats.cmd_set / mem_stats.uptime * 5 < (db_stats.Com_insert.Value + db_stats.Com_update.Value) / db_stats.Uptime.Value %} class="invalid"{% endif %}>Cache:</td>
231
+                <td>{{ (mem_stats.cmd_set / mem_stats.uptime)|number_format(5) }}/s</td>
232
+            </tr>
233
+            <tr>
234
+                <td>Database:</td>
235
+                <td>{{ ((db_stats.Com_insert.Value + db_stats.Com_update.Value) / db_stats.Uptime.Value)|number_format(5) }}/s</td>
236
+            </tr>
237
+            <tr><td colspan="2"></td></tr>
238
+            <tr><td colspan="2"><strong>Get/Select</strong></td></tr>
239
+            <tr>
240
+                <td>Cache:</td>
241
+                <td>{{ (mem_stats.get_hits / mem_stats.uptime)|number_format(5) }}/s</td>
242
+            </tr>
243
+            <tr>
244
+                <td>Database:</td>
245
+                <td>{{ (db_stats.Com_select.Value / db_stats.Uptime.Value)|number_format(5) }}/s</td>
246
+            </tr>
247
+            <tr><td colspan="2"><strong>Set/Insert</strong></td></tr>
248
+            <tr>
249
+                <td>Cache:</td>
250
+                <td>{{ (mem_stats.cmd_set / mem_stats.uptime)|number_format(5) }}/s</td>
251
+            </tr>
252
+            <tr>
253
+                <td>Database:</td>
254
+                <td>{{ (db_stats.Com_insert.Value / db_stats.Uptime.Value)|number_format(5) }}/s</td>
255
+            </tr>
256
+            <tr>
257
+                <td>Cache increment:</td>
258
+                <td>{{ (mem_stats.incr_hits / mem_stats.uptime)|number_format(5) }}/s</td>
259
+            </tr>
260
+            <tr>
261
+                <td>Cache decrement:</td>
262
+                <td>{{ (mem_stats.decr_hits / mem_stats.uptime)|number_format(5) }}/s</td>
263
+            </tr>
264
+            <tr><td colspan="2"><strong>CAS/Updates</strong></td></tr>
265
+            <tr>
266
+                <td>Cache:</td>
267
+                <td>{{ (mem_stats.cas_hits / mem_stats.uptime)|number_format(5) }}/s</td>
268
+            </tr>
269
+            <tr>
270
+                <td>Database:</td>
271
+                <td>{{ (db_stats.Com_update.Value / db_stats.Uptime.Value)|number_format(5) }}/s</td>
272
+            </tr>
273
+            <tr><td colspan="2"><strong>Deletes</strong></td></tr>
274
+            <tr>
275
+                <td>Cache:</td>
276
+                <td>{{ (mem_stats.delete_hits / mem_stats.uptime)|number_format(5) }}/s</td>
277
+            </tr>
278
+            <tr>
279
+                <td>Database:</td>
280
+                <td>{{ (db_stats.Com_delete.Value / db_stats.Uptime.Value)|number_format(5) }}/s</td>
281
+            </tr>
282
+            <tr><td colspan="2"></td></tr>
283
+            <tr><td colspan="2"><strong>Special</strong></td></tr>
284
+            <tr>
285
+                <td>Expired unfetched:</td>
286
+                <td>{{ (mem_stats.expired_unfetched / mem_stats.uptime)|number_format(5) }}/s</td>
287
+            </tr>
288
+            <tr>
289
+                <td>Evicted unfetched:</td>
290
+                <td>{{ (mem_stats.evicted_unfetched / mem_stats.uptime)|number_format(5) }}/s</td>
291
+            </tr>
292
+            <tr>
293
+                <td>Evicted:</td>
294
+                <td>{{ (mem_stats.evictions / mem_stats.uptime)|number_format(5) }}/s</td>
295
+            </tr>
296
+            <tr>
297
+                <td>Slabs moved:</td>
298
+                <td>{{ (mem_stats.slabs_moved / mem_stats.uptime)|number_format(5) }}/s</td>
299
+            </tr>
300
+            <tr>
301
+                <td>Database slow:</td>
302
+                <td>{{ (db_stats.Slow_queries.Value / db_stats.Uptime.Value)|number_format(5) }}/s</td>
303
+            </tr>
304
+            <tr><td colspan="2"></td></tr>
305
+            <tr><td colspan="2"><strong>Data read</strong></td></tr>
306
+            <tr>
307
+                <td>Cache:</td>
308
+                <td>{{ (mem_stats.bytes_read / mem_stats.uptime)|octet_size }}/s</td>
309
+            </tr>
310
+            <tr>
311
+                <td>Database:</td>
312
+                <td>{{ (db_stats.Bytes_received.Value / db_stats.Uptime.Value)|octet_size }}/s</td>
313
+            </tr>
314
+            <tr><td colspan="2"><strong>Data write</strong></td></tr>
315
+            <tr>
316
+                <td>Cache:</td>
317
+                <td>{{ (mem_stats.bytes_written / mem_stats.uptime)|octet_size }}/s</td>
318
+            </tr>
319
+            <tr>
320
+                <td>Database:</td>
321
+                <td>{{ (db_stats.Bytes_sent.Value / db_stats.Uptime.Value)|octet_size }}/s</td>
322
+            </tr>
323
+        </table>
324
+    </div>
325
+</div>

+ 100
- 0
templates/admin/cache-management.twig View File

@@ -0,0 +1,100 @@
1
+<div class="header">
2
+    <h2>View or flush cache keys</h2>
3
+</div>
4
+<div class="thin pad">
5
+
6
+{% if result %}
7
+    <div class="box pad">
8
+        <h2>{% if flushed %}Cache flushed{% else %}Cache contents{% endif %}</h2>
9
+        <table>
10
+        <tr><th>Name</th><th>Value</th><tr>
11
+    {% for name, value in result %}
12
+        <tr><td style="vertical-align: top">{{ name }}</td>
13
+        {% if flushed %}
14
+            {% if multi %}
15
+        <td>Flushed {{ value|number_format }} key{{ value|plural }} in this namespace</td>
16
+            {% else %}
17
+        <td>{{ value }}</td>
18
+            {% endif %}
19
+        {% else %}
20
+        <td style="overflow: scroll; max-width: 400px;">
21
+            {%- if value is null -%}
22
+            <tt>null</tt>
23
+            {%- elseif value is iterable -%}
24
+            {{- dump(value) -}}
25
+            {%- elseif value == false -%}
26
+            <tt>false</tt>
27
+            {%- else -%}
28
+            {{- value -}}
29
+            {%- endif -%}
30
+        </td>
31
+        {% endif %}
32
+        </tr>
33
+    {% endfor %}
34
+    {% if flushed %}
35
+        <tr><td colspan="2">Flush performed in
36
+        {%- if delta > 1 %} {{ delta|number_format(3) }} sec</td></tr>
37
+        {%- else %} {{ (delta*1000)|number_format(3) }} msec
38
+        {%- endif %}</td></tr>
39
+    {% endif %}
40
+        </table>
41
+    </div>
42
+{% endif %}
43
+
44
+    <div class="box pad">
45
+    <h2>Inspection</h2>
46
+    <form class="manage_form" name="cache" method="get" action="">
47
+        <input type="hidden" name="action" value="clear_cache" />
48
+        <p>View or flush keys (separated by spaces). Remember to check the checkbox to validate that you really want to flush content.</p>
49
+        <textarea cols="80" rows="8" name="key" id="key" class="inputtext">{{ key }}</textarea><br />
50
+        <span style="padding: 0 0"><input type="submit" name="view" value="View" /></span>
51
+        <span style="padding: 0 20px"><input type="submit" name="json" value="View as JSON" /></span>
52
+{% if can_flush %}
53
+        <span style="padding: 0 15px"><input type="checkbox" name="check" /> <input type="submit" name="flush" value="Flush" /></span>
54
+{% endif %}
55
+    </form>
56
+    </div>
57
+{% if can_flush %}
58
+    <div class="box pad">
59
+    <h2>Bulk eraser</h2>
60
+        <p>Flush collections. Warning: may be so slow as to cause a gateway timeout, but the process will complete.</p>
61
+        <form class="manage_form" name="cache" action="">
62
+        <input type="hidden" name="action" value="clear_cache" />
63
+        <table>
64
+            <tr>
65
+{% for name in namespace|keys %}
66
+                <th width="{{ 100/(namespace|length) }}%">{{ name }}</th>
67
+{% endfor %}
68
+            </tr>
69
+{% for list in namespace %}
70
+                <td style="vertical-align: top">
71
+    {% for field, shape in list %}
72
+                    <label><input type="checkbox" name="{{ field }}" id="flush-{{ field }}" checked="checked" /> {{ shape|replace({'%d': '*'}) }}</label>
73
+                    <br />
74
+    {% endfor %}
75
+                </td>
76
+{% endfor %}
77
+            <tr>
78
+                <td colspan="{{ namespace|length }}">If you also want to flush a specfic collection (or more) that is not listed,
79
+                you may write it in below (e.g. <tt>artist_foo_*</tt>, space separated, in the appropriate column).</td>
80
+            </tr>
81
+            <tr>
82
+{% for name in namespace|keys %}
83
+                <td>write-in<br />
84
+                    <textarea cols="{{ 90/(namespace|length) }}" rows="3" name="{{ name }}-free" id="{{ name }}-free" class="inputtext"></textarea><br />
85
+                </td>
86
+{% endfor %}
87
+            </tr>
88
+            <tr>
89
+{% for name in namespace|keys %}
90
+                <td align="center">
91
+                    <input type="submit" name="flush-{{ name }}" value="Flush checked" /></span>
92
+                </td>
93
+{% endfor %}
94
+            </tr>
95
+        </table>
96
+    <form class="manage_form" name="eraser" action="">
97
+    </form>
98
+    </div>
99
+{% endif %}
100
+</div>

+ 51
- 0
templates/admin/changelog.twig View File

@@ -0,0 +1,51 @@
1
+<div class="thin">
2
+    <h2>{{ constant('SITE_NAME') }} Change Log</h2>
3
+    {{ paginator.linkbox|raw }}
4
+{% if is_mod %}
5
+    <div class="box box2 edit_changelog">
6
+        <div class="head">
7
+            <strong>Manually submit a new change to the change log</strong>
8
+        </div>
9
+        <div class="pad">
10
+            <form method="post" action="">
11
+                <input type="hidden" name="perform" value="add" />
12
+                <input type="hidden" name="auth" value="{{ auth }}" />
13
+                <div class="field_div" id="cl_message">
14
+                    <span class="label">Commit message:</span>
15
+                    <br />
16
+                    <textarea name="message" rows="2"></textarea>
17
+                </div>
18
+                <div class="field_div" id="cl_author">
19
+                    <span class="label">Author:</span>
20
+                    <br />
21
+                    <input type="text" name="author" value="{{ author }}" />
22
+                </div>
23
+                <div class="submit_div" id="cl_submit">
24
+                    <input type="submit" value="Submit" />
25
+                </div>
26
+            </form>
27
+        </div>
28
+    </div>
29
+{% endif %}
30
+{% for change in list %}
31
+    <div class="box box2 change_log_entry">
32
+        <div class="head">
33
+            <span>{{ change.date }} by {{ change.author }}</span>
34
+    {% if is_mod %}
35
+            <span style="float: right;">
36
+                <form id="delete_{{ change.id }}" method="post" action="">
37
+                    <input type="hidden" name="perform" value="remove" />
38
+                    <input type="hidden" name="auth" value="{{ auth }}" />
39
+                    <input type="hidden" name="change_id" value="{{ change.id }}" />
40
+                </form>
41
+                <a href="#" onclick="$('#delete_{{ change.id }}').raw().submit(); return false;" class="brackets">Delete</a>
42
+            </span>
43
+    {% endif %}
44
+        </div>
45
+        <div class="pad">
46
+            {{ change.message }}
47
+        </div>
48
+    </div>
49
+{% endfor %}
50
+{{ paginator.linkbox|raw }}
51
+</div>

+ 53
- 0
templates/admin/client-whitelist.twig View File

@@ -0,0 +1,53 @@
1
+<div class="header">
2
+    <h2>Client Whitelist</h2>
3
+</div>
4
+<div class="box2 pad thin">
5
+<form class="add_form" name="clients" action="" method="post">
6
+    <input type="hidden" name="action" value="whitelist_alter" />
7
+    <input type="hidden" name="auth" value="{{ auth }}" />
8
+    <table>
9
+        <tr class="colhead">
10
+            <td colspan="4">Add client</td>
11
+        </tr>
12
+        <tr class="rowa">
13
+            <td>
14
+                <input type="text" size="60" name="client" placeholder="Client name" />
15
+            </td>
16
+            <td>
17
+                <input type="text" size="10" name="peer_id" placeholder="Peer ID" />
18
+            </td>
19
+            <td>
20
+                <input type="submit" value="Create" />
21
+            </td>
22
+        </tr>
23
+    </table>
24
+</form>
25
+<table width="100%">
26
+    <tr class="colhead">
27
+        <td>Client</td>
28
+        <td>Peer ID</td>
29
+        <td>Submit</td>
30
+    </tr>
31
+</table>
32
+{% for c in list %}
33
+<form class="manage_form" name="clients" action="" method="post">
34
+    <input type="hidden" name="action" value="whitelist_alter" />
35
+    <input type="hidden" name="auth" value="{{ auth }}" />
36
+    <table>
37
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
38
+            <td>
39
+                <input type="hidden" name="id" value="{{ c.client_id }}" />
40
+                <input type="text" size="60" name="client" value="{{ c.vstring }}" />
41
+            </td>
42
+            <td>
43
+                <input type="text" size="10" name="peer_id" value="{{ c.peer_id }}" />
44
+            </td>
45
+            <td>
46
+                <input type="submit" name="submit" value="Edit" />
47
+                <input type="submit" name="submit" value="Delete" />
48
+            </td>
49
+        </tr>
50
+    </table>
51
+</form>
52
+{% endfor %}
53
+</div>

+ 42
- 0
templates/admin/db-table.twig View File

@@ -0,0 +1,42 @@
1
+<div class="linkbox">
2
+    <a href="tools.php?action=database_specifics" class="brackets">Database specifics</a>
3
+</div>
4
+
5
+<div class="pad"><div class="box pad">
6
+    <h3>Table definition</h3>
7
+    <pre>{{ definition }}</pre>
8
+</div></div>
9
+
10
+<div class="pad"><div class="box pad">
11
+    <h3>Rows read</h3>
12
+    <table>
13
+        <tr>
14
+            <th>Rows read</th>
15
+            <th>Rows changed</th>
16
+            <th>Rows changed per index</th>
17
+        </tr>
18
+{% for r in table_read %}
19
+        <tr>
20
+            <td>{{ r.ROWS_READ|number_format }}</td>
21
+            <td>{{ r.ROWS_CHANGED|number_format }}</td>
22
+            <td>{{ r.ROWS_CHANGED_X_INDEXES|number_format }}</td>
23
+        </tr>
24
+{% endfor %}
25
+    </table>
26
+</div></div>
27
+
28
+<div class="pad"><div class="box pad">
29
+    <h3>Index reads</h3>
30
+    <table>
31
+        <tr>
32
+            <th>Index name</th>
33
+            <th>Rows read</th>
34
+        </tr>
35
+{% for r in index_read %}
36
+        <tr>
37
+            <td>{{ r.INDEX_NAME }}</td>
38
+            <td>{{ r.ROWS_READ|number_format }}</td>
39
+        </tr>
40
+{% endfor %}
41
+    </table>
42
+</div></div>

+ 26
- 0
templates/admin/duplicate-ipaddr.twig View File

@@ -0,0 +1,26 @@
1
+{% from 'macro/ipv4.twig' import ajax_ipv4 %}
2
+
3
+{% if list is empty %}
4
+<h2 align="center">There are currently no users with more than {{ overlap }} IP overlaps.</h2>
5
+{% else %}
6
+{{ paginator.linkbox|raw }}
7
+<table width="100%">
8
+    <tr class="colhead">
9
+        <td>User</td>
10
+        <td>IP address</td>
11
+        <td>Dupes</td>
12
+        <td>Joined</td>
13
+    </tr>
14
+{% for item in list %}
15
+    <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
16
+        <td>{{ item.user_id|user_full }}</td>
17
+        <td>
18
+            <span style="float: left;">{{ ajax_ipv4(item.ipaddr) }} ({{ item.ipaddr }})</span><span style="float: right;"><a href="userhistory.php?action=ips&amp;userid={{ item.user_id }}" title="History" class="brackets tooltip">H</a> <a href="user.php?action=search&amp;ip_history=on&amp;ip={{ item.ipaddr }}" title="Search" class="brackets tooltip">S</a></span>
19
+        </td>
20
+        <td>{{ item.uses|number_format }}</td>
21
+        <td>{{ item.joined|time_diff }}</td>
22
+    </tr>
23
+{% endfor %}
24
+</table>
25
+{{ paginator.linkbox|raw }}
26
+{% endif %}

+ 79
- 0
templates/admin/history-ip-tracker.twig View File

@@ -0,0 +1,79 @@
1
+<div class="thin">
2
+    <div class="header">
3
+{% if user  %}
4
+        <h2><a href="user.php?id={{ user.id }}">{{ user.username }}</a> &rsaquo; Tracker IP History</h2>
5
+{% else %}
6
+        <h2>IP address {{ ipaddr }} &rsaquo; Tracker IP History</h2>
7
+{% endif %}
8
+    </div>
9
+
10
+{% for s in summary %}
11
+    {% if loop.first %}
12
+    <div class="header">
13
+        <h3>Summary</h3>
14
+    </div>
15
+    <table>
16
+        <tr class="colhead">
17
+        {% if is_mod %}
18
+            <td title="Click on an address to view list of users seen on that address">IP address</td>
19
+        {% else %}
20
+            <td>IP address</td>
21
+        {% endif %}
22
+            <td>Total</td>
23
+            <td>First Seen</td>
24
+            <td>Last Seen</td>
25
+        </tr>
26
+    {% endif %}
27
+        <tr>
28
+    {% if is_mod %}
29
+            <td><a href="{{ urlstem }}ip={{ s.IP }}">{{ s.IP }}</a></td>
30
+    {% else %}
31
+            <td>">{{ s.IP }}</td>
32
+    {% endif %}
33
+            <td>{{ s.total|number_format }}</td>
34
+            <td>{{ s.first|time_diff }}</td>
35
+            <td>{{ s.last|time_diff }}</td>
36
+    {% if loop.last %}
37
+    </table>
38
+    {% endif %}
39
+{% endfor %}
40
+
41
+    <div class="header">
42
+        <h3>Detail</h3>
43
+    </div>
44
+
45
+    {{ paginator.linkbox|raw }}
46
+
47
+    <table>
48
+        <tr class="colhead">
49
+{% if user %}
50
+            <td>IP address</td>
51
+{% else %}
52
+            <td>Username</td>
53
+{% endif %}
54
+            <td>Torrent</td>
55
+            <td>Time</td>
56
+        </tr>
57
+{% for r in details %}
58
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
59
+            <td>
60
+    {% if user %}
61
+            {{ r.IP }} ({{ resolveCountryIpv4(r.ip) }}) {{ resolveIpv4(r.ip) }}
62
+            <a href="http://whatismyipaddress.com/ip/{{ r.ip }}" class="brackets tooltip" title="Search WIMIA.com">WI</a>
63
+    {% else %}
64
+            <a href="{{ urlstem }}userid={{ r.uid }}">{{ r.username }}</a>
65
+    {% endif %}
66
+            </td>
67
+            <td><a href="torrents.php?torrentid={{ r.fid }}">{{ r.name }}</a></td>
68
+            <td>{{ r.date|time_diff }}</td>
69
+        </tr>
70
+{% endfor %}
71
+    </table>
72
+    {{ paginator.linkbox|raw }}
73
+</div>
74
+
75
+<script type="text/javascript">
76
+function ShowIPs(rowname) {
77
+    $('tr[name="'+rowname+'"]').gtoggle();
78
+}
79
+</script>

+ 116
- 0
templates/admin/login-watch.twig View File

@@ -0,0 +1,116 @@
1
+{% from 'macro/form.twig' import checked %}
2
+
3
+<div class="thin">
4
+<div class="header">
5
+    <h2>Login Watch Management</h2>
6
+</div>
7
+<div class="linkbox">
8
+    <a href="tools.php?action=ip_ban">IP Address Bans</a>
9
+</div>
10
+
11
+{% if nr_ban or nr_clear %}
12
+<div class="pad box">
13
+    {% if nr_ban %}
14
+    IP addresses banned: {{ nr_ban }}
15
+    {% endif %}
16
+    {% if nr_clear %}
17
+    IP addresses cleared: {{ nr_clear }}
18
+    {% endif %}
19
+</div>
20
+{% endif %}
21
+
22
+{% if list is empty %}
23
+<div class="pad box">
24
+    There are no current login watches.
25
+</div>
26
+{% else %}
27
+{{ paginator.linkbox|raw }}
28
+{% for b in list %}
29
+    {% if loop.first %}
30
+<form class="manage_form" name="bans" action="" method="post">
31
+<input type="hidden" name="auth" value="{{ auth }}" />
32
+<input type="hidden" name="action" value="login_watch" />
33
+<table width="100%">
34
+    <tr class="colhead">
35
+        <td>{{ header.ipaddr|raw }}</td>
36
+        <td>DNS</td>
37
+        <td>{{ header.user|raw }}</td>
38
+        <td>{{ header.attempts|raw }}</td>
39
+        <td>{{ header.bans|raw }}</td>
40
+        <td>{{ header.last_attempt|raw }}</td>
41
+        <td>{{ header.banned_until|raw }}</td>
42
+        <td>Clear</td>
43
+        {% if can_ban %}
44
+        <td>Ban</td>
45
+        <td>Do nothing</td>
46
+        {% endif %}
47
+
48
+    </tr>
49
+    {% endif %}
50
+    <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
51
+        <td>
52
+            {{ b.ipaddr|raw }}
53
+            <a href="https://whatismyipaddress.com/ip/{{ b.ipaddr }}" class="brackets tooltip" title="whatismyipaddress.com" target="_blank">WI</a>
54
+        </td>
55
+        <td>
56
+            {{ b.dns }}
57
+        </td>
58
+        <td>
59
+    {% if b.user_id %}
60
+            {{ b.user_id|user_url }}
61
+    {% else %}
62
+            <i title="no user with this name">{{ b.capture }}</i>
63
+    {% endif %}
64
+        </td>
65
+        <td>
66
+            {{ b.attempts }}
67
+        </td>
68
+        <td>
69
+            {{ b.bans }}
70
+        </td>
71
+        <td>
72
+            {{ b.last_attempt|time_diff }}
73
+        </td>
74
+        <td>
75
+            {{ b.banned_until|time_diff }}
76
+        </td>
77
+    {% if can_ban %}
78
+        <td style="text-align: center">
79
+            <input type="radio" name="admin-{{ b.id }}" value="clear" />
80
+        </td>
81
+        <td style="text-align: center">
82
+            <input type="radio" name="admin-{{ b.id }}" value="ban" />
83
+        </td>
84
+        <td style="text-align: center">
85
+            <input type="radio" id="noop-{{ b.id }}" name="admin-{{ b.id }}" value="noop" checked="checked" />
86
+        </td>
87
+    {% else %}
88
+        <td>
89
+            <input type="checkbox" name="clear-{{ b.id }}" />
90
+        </td>
91
+    {% endif %}
92
+    {% if loop.last %}
93
+        {% if can_ban %}
94
+    <tr>
95
+        <td><br />Ban Reason</td>
96
+        <td colspan="9">
97
+            <br />
98
+            <input type="text" name="reason" size="40" />
99
+            <br />When banning, this reason will be recorded for each checked IP address.
100
+        </td>
101
+    </tr>
102
+        {% endif %}
103
+    <tr>
104
+        <td colspan="10">
105
+            <input type="checkbox" id="resolve" name="resolve"{{ checked(resolve) }}
106
+            />&nbsp;<label for="resolve">Resolve IP addresses (may be slow)</label><br />
107
+            <input type="submit" name="submit" value="Update" />
108
+        </td>
109
+    </tr>
110
+</table>
111
+</form>
112
+    {% endif %}
113
+{% endfor %}
114
+{{ paginator.linkbox|raw }}
115
+{% endif %}
116
+</div>

+ 229
- 0
templates/admin/notification-sandbox.twig View File

@@ -0,0 +1,229 @@
1
+{% macro artistlist(list) %}
2
+{% if list is empty -%}
3
+    <i>none</i>
4
+{%- else %}
5
+    {%- for a in list -%}
6
+        {%- if not loop.first -%}
7
+        <br />
8
+        {% endif -%}
9
+        {{ a.name }}
10
+    {%- endfor %}
11
+{% endif %}
12
+{% endmacro %}
13
+
14
+<div class="thin">
15
+    <div class="header">
16
+        <h2>Notifications Sandbox</h2>
17
+    </div>
18
+{% if group %}
19
+    <div class="box pad">
20
+    <h4>Results {{ manager.artistHtml|raw }} - <a href="/torrents.php?id={{ group.ID }}">{{ group.Name|raw }}</a></h4>
21
+
22
+<table><tr>
23
+    <td style="vertical-align: top"><table>
24
+        <tr><td class="label" colspan="2" style="text-align: center">Release details</td></tr>
25
+        <tr>
26
+            <td class="label">Uploaded by</td>
27
+            <td>{{ torrent.UserID|user_full }}</td>
28
+        </tr>
29
+        <tr>
30
+            <td class="label">Category</td>
31
+            <td>{{ category }}</td>
32
+        </tr>
33
+        <tr>
34
+            <td class="label">Release Type</td>
35
+            <td>{{ release }}</td>
36
+        </tr>
37
+        <tr>
38
+            <td class="label">Media</td>
39
+            <td>{{ torrent.Media }}</td>
40
+        </tr>
41
+        <tr>
42
+            <td class="label">Format</td>
43
+            <td>{{ torrent.Format }}</td>
44
+        </tr>
45
+        <tr>
46
+            <td class="label">Encoding</td>
47
+            <td>{{ torrent.Encoding }}</td>
48
+        </tr>
49
+        <tr>
50
+            <td class="label">Year</td>
51
+            <td>{{ year }}</td>
52
+        </tr>
53
+        <tr>
54
+            <td class="label">Record Label</td>
55
+            <td>{{ label }}</td>
56
+        </tr>
57
+        <tr>
58
+            <td class="label">Tags</td>
59
+            <td>{{ tags }}</td>
60
+        </tr>
61
+    </table></td>
62
+    <td style="vertical-align: top"><table>
63
+        <tr><td class="label" colspan="2" style="text-align: center">Artist details</td></tr>
64
+        <tr>
65
+            <td class="label">Main</td>
66
+            <td>
67
+                {{ _self.artistlist(manager.artistRole.main) }}
68
+            </td>
69
+        </tr>
70
+        <tr>
71
+            <td class="label">Composers</td>
72
+            <td>
73
+                {{ _self.artistlist(manager.artistRole.composer) }}
74
+            </td>
75
+        </tr>
76
+        <tr>
77
+            <td class="label">Conductors</td>
78
+            <td>
79
+                {{ _self.artistlist(manager.artistRole.conductor) }}
80
+            </td>
81
+        </tr>
82
+        <tr>
83
+            <td class="label">Remixers</td>
84
+            <td>
85
+                {{ _self.artistlist(manager.artistRole.dj) }}
86
+            </td>
87
+        </tr>
88
+        <tr>
89
+            <td class="label">DJs</td>
90
+            <td>
91
+                {{ _self.artistlist(manager.artistRole.dj) }}
92
+            </td>
93
+        </tr>
94
+        <tr>
95
+            <td class="label">Producers</td>
96
+            <td>
97
+                {{ _self.artistlist(manager.artistRole.producer) }}
98
+            </td>
99
+        </tr>
100
+        <tr>
101
+            <td class="label">Arrangers</td>
102
+            <td>
103
+                {{ _self.artistlist(manager.artistRole.arranger) }}
104
+            </td>
105
+        </tr>
106
+        <tr>
107
+            <td class="label">Guests</td>
108
+            <td>
109
+                {{ _self.artistlist(manager.artistRole.guest) }}
110
+            </td>
111
+        </tr>
112
+    </table></td>
113
+</tr>
114
+{% if sql %}
115
+<tr>
116
+    <td colspan="2"><code>{{ sql }}</code></td>
117
+<tr>
118
+<tr>
119
+    <td colspan="2">
120
+    {% for arg in args %}
121
+        {{ arg }}{% if not loop.last %}<br />{% endif %}
122
+    {% endfor %}
123
+    </td>
124
+<tr>
125
+{% endif %}
126
+</table>
127
+</div>
128
+
129
+{% if result %}
130
+<div class="box pad">
131
+<table>
132
+    <tr>
133
+        <th>User ID</th>
134
+        <th>Filter ID</th>
135
+        <th>Name</th>
136
+        <th>Artists</th>
137
+        <th>Year</th>
138
+        <th>Tags</th>
139
+        <th>Not Tags</th>
140
+        <th>Formats</th>
141
+        <th>Encodings</th>
142
+        <th>Media</th>
143
+        <th>Users</th>
144
+        <th>Exclude VA</th>
145
+        <th>New groups only</th>
146
+    </tr>
147
+    {% for r in result %}
148
+    <tr>
149
+        <td class="vertical-align: top;">{{ r.user_id|user_url }}</td>
150
+        <td class="vertical-align: top;">{{ r.filter_id }}</td>
151
+        <td class="vertical-align: top;">{{ r.filter.info.label}}</td>
152
+        <td class="vertical-align: top;">
153
+        {% for artist in r.filter.info.artist|sort %}
154
+            {{ artist }}{% if not loop.last %} &middot;{% endif %}
155
+        {% endfor %}
156
+        </td>
157
+        <td class="vertical-align: top;">
158
+        {% if r.filter.info.from_year or r.filter.info.to_year -%}
159
+            {{ r.filter.info.from_year }}-{{ r.filter.info.to_year }}
160
+        {% endif %}
161
+        </td>
162
+        <td class="vertical-align: top;">
163
+        {% for tag in r.filter.info.tag|sort %}
164
+            {{ tag }}{% if not loop.last %}<br />{% endif %}
165
+        {% endfor %}
166
+        </td>
167
+        <td class="vertical-align: top;">
168
+        {% for notTag in r.filter.info.notTag|sort %}
169
+            {{ notTag }}{% if not loop.last %}<br />{% endif %}
170
+        {% endfor %}
171
+        </td>
172
+        <td class="vertical-align: top;">
173
+        {% for format in r.filter.info.format|sort %}
174
+            {{ format }}{% if not loop.last %}<br />{% endif %}
175
+        {% endfor %}
176
+        </td>
177
+        <td class="vertical-align: top;">
178
+        {% for encoding in r.filter.info.encoding|sort %}
179
+            <span style="white-space: nowrap">{{ encoding }}</span>{% if not loop.last %}<br />{% endif %}
180
+        {% endfor %}
181
+        </td>
182
+        <td class="vertical-align: top;">
183
+        {% for media in r.filter.info.media|sort %}
184
+            {{ media }}{% if not loop.last %}<br />{% endif %}
185
+        {% endfor %}
186
+        </td>
187
+        <td class="vertical-align: top;">
188
+        {% for user in r.filter.info.user|sort %}
189
+            {{ user|user_url }}{% if not loop.last %}<br />{% endif %}
190
+        {% endfor %}
191
+        </td>
192
+        <td class="vertical-align: top;">{{ r.filter.info.exclude_va }}</td>
193
+        <td class="vertical-align: top;">{{ r.filter.info.new_groups_only }}</td>
194
+    </tr>
195
+    {% endfor %}
196
+</table>
197
+</div>
198
+{% endif %}
199
+
200
+{% endif %}
201
+<div class="box pad">
202
+    <form class="send_form" action="" method="post">
203
+        <input type="hidden" name="action" value="notification_sandbox" />
204
+        <table class="layout">
205
+            <tbody>
206
+                <tr>
207
+                    <td class="label">
208
+                        <label for="torrentid">Torrent ID</label>
209
+                    </td>
210
+                    <td>
211
+                        <input type="text" name="torrentid" value="{{ torrent.ID }}" /> (<b>not</b> group ID!)
212
+                    </td>
213
+                <tr>
214
+                </tr>
215
+                    <td class="label">
216
+                        <label for="torrentid">optional notified User ID</label>
217
+                    </td>
218
+                    <td>
219
+                        <input type="text" name="notifiedid" value="{{ notified_id }}" />&nbsp;(To limit results to one person)
220
+                        <br />Use <tt>@name</tt> for a username, otherwise (numeric) user ID.
221
+                    </td>
222
+                    </td>
223
+                </tr>
224
+            </tbody>
225
+        </table>
226
+        <input type="submit" value="Submit" />
227
+    </form>
228
+</div>
229
+</div>

+ 179
- 0
templates/admin/privilege-list.twig View File

@@ -0,0 +1,179 @@
1
+<div class="permissions">
2
+    <div class="permission_container">
3
+        <table>
4
+            <tr class="colhead">
5
+                <td>Site</td>
6
+            </tr>
7
+            <tr>
8
+                <td>
9
+                    {{ privilege(default, user, 'site_leech') }}
10
+                    {{ privilege(default, user, 'site_upload') }}
11
+                    {{ privilege(default, user, 'site_vote') }}
12
+                    {{ privilege(default, user, 'site_submit_requests') }}
13
+                    {{ privilege(default, user, 'site_advanced_search') }}
14
+                    {{ privilege(default, user, 'site_top10') }}
15
+                    {{ privilege(default, user, 'site_torrents_notify') }}
16
+                    {{ privilege(default, user, 'site_collages_create') }}
17
+                    {{ privilege(default, user, 'site_collages_manage') }}
18
+                    {{ privilege(default, user, 'site_collages_delete') }}
19
+                    {{ privilege(default, user, 'site_collages_subscribe') }}
20
+                    {{ privilege(default, user, 'site_collages_personal') }}
21
+                    {{ privilege(default, user, 'site_collages_renamepersonal') }}
22
+                    {{ privilege(default, user, 'site_advanced_top10') }}
23
+                    {{ privilege(default, user, 'site_album_votes') }}
24
+                    {{ privilege(default, user, 'site_make_bookmarks') }}
25
+                    {{ privilege(default, user, 'site_edit_wiki') }}
26
+                    {{ privilege(default, user, 'site_can_invite_always') }}
27
+                    {{ privilege(default, user, 'site_send_unlimited_invites') }}
28
+                    {{ privilege(default, user, 'site_moderate_requests') }}
29
+                    {{ privilege(default, user, 'site_admin_requests') }}
30
+                    {{ privilege(default, user, 'site_delete_artist') }}
31
+                    {{ privilege(default, user, 'site_view_flow') }}
32
+                    {{ privilege(default, user, 'site_view_full_log') }}
33
+                    {{ privilege(default, user, 'site_view_torrent_snatchlist') }}
34
+                    {{ privilege(default, user, 'site_delete_tag') }}
35
+                    {{ privilege(default, user, 'site_disable_ip_history') }}
36
+                    {{ privilege(default, user, 'zip_downloader') }}
37
+                    {{ privilege(default, user, 'site_debug') }}
38
+                    {{ privilege(default, user, 'site_analysis') }}
39
+                    {{ privilege(default, user, 'site_database_specifics') }}
40
+                    {{ privilege(default, user, 'site_proxy_images') }}
41
+                    {{ privilege(default, user, 'site_search_many') }}
42
+                    {{ privilege(default, user, 'site_collages_recover') }}
43
+                    {{ privilege(default, user, 'site_tag_aliases_read') }}
44
+                    {{ privilege(default, user, 'site_user_stats') }}
45
+                    {{ privilege(default, user, 'site_unlimit_ajax') }}
46
+                    {{ privilege(default, user, 'site_archive_ajax') }}
47
+                </td>
48
+            </tr>
49
+        </table>
50
+    </div>
51
+    <div class="permission_container">
52
+        <table>
53
+            <tr class="colhead">
54
+                <td>Users</td>
55
+            </tr>
56
+            <tr>
57
+                <td>
58
+                    * Only applies to users with the same or lower class level<br />
59
+                    {{ privilege(default, user, 'users_edit_usernames') }}
60
+                    {{ privilege(default, user, 'users_edit_ratio') }}
61
+                    {{ privilege(default, user, 'users_edit_own_ratio') }}
62
+                    {{ privilege(default, user, 'users_edit_titles') }}
63
+                    {{ privilege(default, user, 'users_edit_avatars') }}
64
+                    {{ privilege(default, user, 'users_edit_invites') }}
65
+                    {{ privilege(default, user, 'users_edit_watch_hours') }}
66
+                    {{ privilege(default, user, 'users_edit_reset_keys') }}
67
+                    {{ privilege(default, user, 'users_edit_profiles') }}
68
+                    {{ privilege(default, user, 'users_view_friends') }}
69
+                    {{ privilege(default, user, 'users_reset_own_keys') }}
70
+                    {{ privilege(default, user, 'users_edit_password') }}
71
+                    {{ privilege(default, user, 'users_promote_below') }}
72
+                    {{ privilege(default, user, 'users_promote_to') }}
73
+                    {{ privilege(default, user, 'users_give_donor') }}
74
+                    {{ privilege(default, user, 'users_warn') }}
75
+                    {{ privilege(default, user, 'users_disable_users') }}
76
+                    {{ privilege(default, user, 'users_disable_any') }}
77
+                    {{ privilege(default, user, 'users_delete_users') }}
78
+                    {{ privilege(default, user, 'users_view_invites') }}
79
+                    {{ privilege(default, user, 'users_view_seedleech') }}
80
+                    {{ privilege(default, user, 'users_view_uploaded') }}
81
+                    {{ privilege(default, user, 'users_view_keys') }}
82
+                    {{ privilege(default, user, 'users_view_ips') }}
83
+                    {{ privilege(default, user, 'users_view_email') }}
84
+                    {{ privilege(default, user, 'users_invite_notes') }}
85
+                    {{ privilege(default, user, 'users_override_paranoia') }}
86
+                    {{ privilege(default, user, 'users_make_invisible') }}
87
+                    {{ privilege(default, user, 'users_logout') }}
88
+                    {{ privilege(default, user, 'users_mod') }}
89
+                </td>
90
+            </tr>
91
+        </table>
92
+        <table>
93
+            <tr class="colhead">
94
+                <td>Forums</td>
95
+            </tr>
96
+            <tr>
97
+                <td>
98
+                    {{ privilege(default, user, 'admin_manage_forums') }}
99
+                    {{ privilege(default, user, 'forums_polls_create') }}
100
+                    {{ privilege(default, user, 'forums_polls_moderate') }}
101
+                    {{ privilege(default, user, 'site_moderate_forums') }}
102
+                    {{ privilege(default, user, 'site_admin_forums') }}
103
+                    {{ privilege(default, user, 'site_forum_post_delete') }}
104
+                    {{ privilege(default, user, 'users_disable_posts') }}
105
+                </td>
106
+            </tr>
107
+        </table>
108
+    </div>
109
+    <div class="permission_container">
110
+        <table>
111
+            <tr class="colhead">
112
+                <td>Torrents</td>
113
+            </tr>
114
+            <tr>
115
+                <td>
116
+                    {{ privilege(default, user, 'torrents_edit') }}
117
+                    {{ privilege(default, user, 'torrents_delete') }}
118
+                    {{ privilege(default, user, 'torrents_delete_fast') }}
119
+                    {{ privilege(default, user, 'torrents_freeleech') }}
120
+                    {{ privilege(default, user, 'torrents_search_fast') }}
121
+                    {{ privilege(default, user, 'torrents_add_artist') }}
122
+                    {{ privilege(default, user, 'edit_unknowns') }}
123
+                    {{ privilege(default, user, 'torrents_edit_vanityhouse') }}
124
+                    {{ privilege(default, user, 'artist_edit_vanityhouse') }}
125
+                    {{ privilege(default, user, 'torrents_hide_dnu') }}
126
+                </td>
127
+            </tr>
128
+        </table>
129
+    </div>
130
+    <div class="permission_container">
131
+        <table>
132
+            <tr class="colhead">
133
+                <td>Administrative</td>
134
+            </tr>
135
+            <tr>
136
+                <td>
137
+                    {{ privilege(default, user, 'admin_manage_news') }}
138
+                    {{ privilege(default, user, 'admin_manage_blog') }}
139
+                    {{ privilege(default, user, 'admin_manage_contest') }}
140
+                    {{ privilege(default, user, 'admin_manage_polls') }}
141
+                    {{ privilege(default, user, 'admin_manage_fls') }}
142
+                    {{ privilege(default, user, 'admin_manage_user_fls') }}
143
+                    {{ privilege(default, user, 'admin_manage_applicants') }}
144
+                    {{ privilege(default, user, 'admin_manage_referrals') }}
145
+                    {{ privilege(default, user, 'admin_view_notifications') }}
146
+                    {{ privilege(default, user, 'admin_view_payments') }}
147
+                    {{ privilege(default, user, 'admin_manage_payments') }}
148
+                    {{ privilege(default, user, 'admin_manage_navigation') }}
149
+                    {{ privilege(default, user, 'admin_periodic_task_manage') }}
150
+                    {{ privilege(default, user, 'admin_periodic_task_view') }}
151
+                    {{ privilege(default, user, 'admin_rate_limit_manage') }}
152
+                    {{ privilege(default, user, 'admin_rate_limit_view') }}
153
+                    {{ privilege(default, user, 'admin_view_referrals') }}
154
+                    {{ privilege(default, user, 'admin_reports') }}
155
+                    {{ privilege(default, user, 'admin_bp_history') }}
156
+                    {{ privilege(default, user, 'admin_fl_history') }}
157
+                    {{ privilege(default, user, 'admin_advanced_user_search') }}
158
+                    {{ privilege(default, user, 'admin_create_users') }}
159
+                    {{ privilege(default, user, 'admin_donor_log') }}
160
+                    {{ privilege(default, user, 'admin_manage_stylesheets') }}
161
+                    {{ privilege(default, user, 'admin_manage_ipbans') }}
162
+                    {{ privilege(default, user, 'admin_dnu') }}
163
+                    {{ privilege(default, user, 'admin_clear_cache') }}
164
+                    {{ privilege(default, user, 'admin_global_notification') }}
165
+                    {{ privilege(default, user, 'admin_whitelist') }}
166
+                    {{ privilege(default, user, 'admin_manage_permissions') }}
167
+                    {{ privilege(default, user, 'admin_recovery') }}
168
+                    {{ privilege(default, user, 'admin_schedule') }}
169
+                    {{ privilege(default, user, 'admin_site_debug') }}
170
+                    {{ privilege(default, user, 'admin_login_watch') }}
171
+                    {{ privilege(default, user, 'admin_manage_wiki') }}
172
+                    {{ privilege(default, user, 'admin_update_geoip') }}
173
+                    {{ privilege(default, user, 'admin_staffpm_stats') }}
174
+                </td>
175
+            </tr>
176
+        </table>
177
+    </div>
178
+    <div class="submit_container"><input type="submit" name="submit" value="Save Permission Class" /></div>
179
+</div>

+ 30
- 0
templates/admin/privilege-matrix.twig View File

@@ -0,0 +1,30 @@
1
+<table width="100%">
2
+    <tr class="colhead">
3
+        <td rowspan="2" style="vertical-align: bottom">Primary Class {{ star|raw }} <br /><br />Privilege</td>
4
+{% for c in class_list %}
5
+        <td style="padding: 0;"><div class="rot90-container"><div class="rot90">
6
+            <a href="tools.php?action=permissions&amp;id={{ c.id }}">{{ c.name }}</a>
7
+        </div></div></td>
8
+{% endfor %}
9
+    </tr>
10
+    <tr class="colhead">
11
+{% for c in class_list %}
12
+        <td style="padding: 0; text-align: center; font-weight: normal;">{{ c.primary ? star|raw : '' }}</td>
13
+{% endfor %}
14
+    </tr>
15
+{% for p in privilege %}
16
+    <tr>
17
+        <td{{ p.orphan ? ' title="This is an orphaned privilege" style="color: orangered; font-weight: bold;"' : '' }} title="{{ p.description }}">{{ p.name }}</td>
18
+{% for c in class_list %}
19
+        <td style="text-align: center;" title="{{ c.name }} {{ c.id in p.can ? 'can' : 'cannot' }} {{ p.description }}">
20
+            <a href="tools.php?action=permissions&amp;id={{ c.id }}">{{ c.id in p.can ? tick : '&middot;' }}</a></td>
21
+{% endfor %}
22
+    </tr>
23
+{% endfor %}
24
+</table>
25
+<br />
26
+
27
+<div class="box pad">Any privileges marked <span style="color: orangered">in
28
+red</span> are orphaned privileges that were found in the database
29
+(in the <tt>permissions.Values</tt> column) but no longer connected to anything
30
+in the code. They should be cleaned out by hand.</div>

+ 48
- 0
templates/admin/ratio-watch.twig View File

@@ -0,0 +1,48 @@
1
+<div class="header">
2
+    <h2>Ratio Watch</h2>
3
+</div>
4
+{% if users is empty %}
5
+<h2 align="center">There are no users currently on ratio watch ({{ total_disabled|number_format }} are already disabled).</h2>
6
+{% else %}
7
+<div class="box pad thin">
8
+    <p>There are currently {{ total|number_format }} enabled users on Ratio Watch and {{ total_disabled|number_format }} already disabled.</p>
9
+</div>
10
+<div class="linkbox">
11
+    {{ pages|raw }}
12
+</div>
13
+<table width="100%">
14
+    <tr class="colhead">
15
+        <td>User</td>
16
+        <td class="number_column">Uploaded</td>
17
+        <td class="number_column">Downloaded</td>
18
+        <td class="number_column">Ratio</td>
19
+        <td class="number_column">Required Ratio</td>
20
+        <td class="number_column tooltip" title="How much the user needs to upload to meet their required ratio">Deficit</td>
21
+        <td class="number_column tooltip" title="How much the user has downloaded on Ratio Watch">Gamble</td>
22
+        <td>Registration Date</td>
23
+        <td class="tooltip" title="If the time shown here ends in &quot;ago&quot;, it represents how long the user has been on ratio watch and/or below their required ratio. Otherwise, it represents the time until the two week Ratio Watch period expires.">Ratio Watch Ended/Ends</td>
24
+    </tr>
25
+    {% for u in users %}
26
+    <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
27
+        <td>{{ u.user_id|user_full }}</td>
28
+        <td class="number_column">{{ u.uploaded|octet_size }}</td>
29
+        <td class="number_column">{{ u.downloaded|octet_size }}</td>
30
+        <td class="number_column">{{ ratio(u.uploaded, u.downloaded)|raw }}</td>
31
+        <td class="number_column">{{ u.required_ration|number_format(2) }}</td>
32
+        <td class="number_column">
33
+            {%- if u.downloaded * u.required_ratio > u.uploaded -%}
34
+            {{ (u.downloaded * u.required_ratio - u.uploaded)|octet_size }}
35
+            {%- else -%}
36
+            &nbsp;
37
+            {%- endif -%}
38
+        </td>
39
+        <td class="number_column">{{ (u.downloaded - u.ratio_watch_downloaded)|octet_size }}</td>
40
+        <td>{{ u.join_date|time_diff }}</td>
41
+        <td>{{ u.ratio_watch_ends|time_diff }}</td>
42
+    </tr>
43
+    {% endfor %}
44
+</table>
45
+<div class="linkbox">
46
+    {{ pages|raw }}
47
+</div>
48
+{% endif %}

+ 135
- 0
templates/admin/registration.twig View File

@@ -0,0 +1,135 @@
1
+<div class="thin">
2
+<div class="box pad">
3
+    <form action="" method="post" acclass="thin box pad">
4
+        <input type="hidden" name="action" value="registration_log" />
5
+        <span style="display: inline-block; width: 90px">Joined after:</span><input type="date" name="after_date" value="{{ after }}" /><br />
6
+        <span style="display: inline-block; width: 90px">Joined before:</span><input type="date" name="before_date" value="{{ before }}" />
7
+        <br />
8
+        <br />
9
+        <input type="submit" value="Search" />
10
+    </form>
11
+</div>
12
+</div>
13
+
14
+{% if not list %}
15
+    <h2 align="center">No new user registrations
16
+{%- else -%}
17
+    <h2 align="center">{{ paginator.total|number_format }} New user registration{{ paginator.total|plural }}
18
+{%- endif %}
19
+{%- if after -%}
20
+    {%- if before %} between {{ after }} and {{ before }}
21
+    {%- else %} after {{ after -}}
22
+    {%- endif -%}
23
+{%- elseif before %} before {{ before -}}
24
+{%- else %} in the last 72 hours
25
+{%- endif -%}
26
+    </h2>
27
+
28
+{% if list %}
29
+    {{ paginator.linkbox|raw }}
30
+    <table width="100%">
31
+        <tr class="colhead">
32
+            <td>User</td>
33
+            <td>Uploaded</td>
34
+            <td>Downloaded</td>
35
+            <td>Ratio</td>
36
+            <td colspan="2">Email</td>
37
+            <td colspan="2">IP address</td>
38
+            <td colspan="2">Host</td>
39
+            <td>Country</td>
40
+            <td>Registered</td>
41
+        </tr>
42
+    {% for user in list %}
43
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
44
+            <td>
45
+                {{ user.id|user_full }}
46
+                <br />
47
+                {{ user.inviter.id|user_full }}
48
+            </td>
49
+            <td style="vertical-align: top">
50
+                {{- user.activityStats.BytesUploaded|octet_size -}}
51
+        {%- if user.inviter -%}
52
+                <br />
53
+                {{- user.inviter.activityStats.BytesUploaded|octet_size -}}
54
+        {%- endif -%}
55
+            </td>
56
+            <td style="vertical-align: top">
57
+                {{- user.ActivityStats.BytesDownloaded|octet_size -}}
58
+        {%- if user.inviter -%}
59
+                <br />
60
+                {{- user.inviter.activityStats.BytesDownloaded|octet_size -}}
61
+        {%- endif -%}
62
+            </td>
63
+            <td style="vertical-align: top">
64
+                {{- ratio(user.activityStats.BytesUploaded, user.ActivityStats.BytesDownloaded) -}}
65
+        {%- if user.inviter -%}
66
+                <br />
67
+                {{- ratio(user.inviter.activityStats.BytesUploaded, user.inviter.ActivityStats.BytesDownloaded) -}}
68
+        {%- endif -%}
69
+            </td>
70
+            <td style="vertical-align: top">
71
+                {{- user.email -}}
72
+                <br />
73
+                {{- user.inviter.email -}}
74
+            </td>
75
+            <td style="vertical-align: top">
76
+                <a href="userhistory.php?action=email&amp;userid={{ user.id }}" title="Email History" class="brackets tooltip">H</a>
77
+                <a href="/user.php?action=search&amp;email_history=on&amp;email={{ user.email }}" title="Email Search" class="brackets tooltip">S</a>
78
+        {%- if user.inviter -%}
79
+                <br />
80
+                <a href="userhistory.php?action=email&amp;userid={{ user.inviter.id }}" title="Email History" class="brackets tooltip">H</a>
81
+                <a href="/user.php?action=search&amp;email_history=on&amp;email={{ user.inviter.email }}" title="Email Search" class="brackets tooltip">S</a>
82
+        {%- endif -%}
83
+            </td>
84
+            <td style="vertical-align: top">
85
+                <span style="float: left">
86
+                {{- user.ipaddr -}}
87
+        {%- if user.inviter.id -%}
88
+                <br />
89
+                {{- user.inviter.ipaddr -}}
90
+        {%- endif -%}
91
+                </span>
92
+        {%- if user.inviter and user.ipaddr == user.inviter.ipaddr -%}
93
+                <span title="IP addresses match" style="float: left; padding: 0px 5px;  color: #ffff00; font-size: large">&#x26A0;</span>
94
+        {%- endif -%}
95
+            </td>
96
+            <td style="vertical-align: top">
97
+                <span style="float: left; padding-left: 2px;" title="Duplicate usage by other users">
98
+                {{- user.duplicateIPv4Count -}}
99
+        {%- if user.inviter and user.ipaddr != user.inviter.ipaddr -%}
100
+                <br />
101
+                {{- user.inviter.duplicateIPv4Count -}}
102
+        {% endif %}
103
+                </span>
104
+            </td>
105
+            <td style="vertical-align: top">
106
+                {{- resolveIpv4(user.ipaddr) -}}
107
+        {% if user.inviter.id and user.inviter.ipaddr != user.ipaddr %}
108
+                <br />
109
+                {{- resolveIpv4(user.inviter.ipaddr) -}}
110
+        {% endif %}
111
+            </td>
112
+            <td style="vertical-align: top">
113
+                <a href="userhistory.php?action=ips&amp;userid{{ user.id }}" title="IP History" class="brackets tooltip">H</a>
114
+                <a href="/user.php?action=search&amp;ip_history=on&amp;ip={{ user.ipaddr }}" title="IP Search" class="brackets tooltip">S</a>
115
+                <a href="http://whatismyipaddress.com/ip/{{ user.ipaddr }}" title="whatismyipaddress.com" class="brackets tooltip">WI</a>
116
+        {% if user.inviter.id and user.inviter.ipaddr != user.ipaddr %}
117
+                <br />
118
+                <a href="userhistory.php?action=ips&amp;userid={{ user.inviter.id }}" title="IP History" class="brackets tooltip">H</a>
119
+                <a href="/user.php?action=search&amp;ip_history=on&amp;ip={{ user.inviter.ipaddr }}" title="IP Search" class="brackets tooltip">S</a>
120
+                <a href="http://whatismyipaddress.com/ip/{{ user.inviter.ipaddr }}" title="WI" class="brackets tooltip">WI</a>
121
+        {% endif %}
122
+            </td>
123
+            <td>
124
+                TODO
125
+            </td>
126
+            <td>
127
+                <span style="white-space: nowrap">{{- user.joinDate|time_diff -}}</span>
128
+                <br />
129
+                <span style="white-space: nowrap">{{- user.inviter.joinDate|time_diff -}}</span>
130
+            </td>
131
+        </tr>
132
+    {% endfor %}
133
+    </table>
134
+    {{ paginator.linkbox|raw }}
135
+{% endif %}

+ 48
- 0
templates/admin/site-info-userrank.twig View File

@@ -0,0 +1,48 @@
1
+</style>
2
+<div class="linkbox">
3
+    <a href="tools.php?action=site_info" class="brackets">Site Information</a>
4
+</div>
5
+<div class="thin">
6
+<h3>User Rank matrix</h3>
7
+
8
+<div class="pad">This table shows how metrics are mapped to percentiles. Taking
9
+the raw value of a user dimension (e.g. 45 uploads), walk down the uploads column
10
+and the first value that is strictly lower than their value (e.g. 44) gives their
11
+rank (in the left hand column). If their value is beneath the last value in the
12
+column then their rank is zero). The data are cached for around one hour.</div>
13
+
14
+<table>
15
+    <tr>
16
+        <th>Rank </th>
17
+{% for n in name %}
18
+        <th style="width: 8.5%; padding: 0;"><div class="rot90-container"><div class="rot90">
19
+            {{ n }}
20
+        </div></div></th>
21
+{% endfor %}
22
+    </tr>
23
+{% for r in range(0, 99) %}
24
+    <tr>
25
+    {% set idx = 100 - r %}
26
+        <td class="number_column">{{ idx }}</td>
27
+    {% for n in name %}
28
+        {% if table[n][idx] is empty %}
29
+        <td class="center">&sdot;</td>
30
+        {% else %}
31
+            {% if n in ['uploaded', 'downloaded', 'bounty'] %}
32
+        <td class="number_column">{{ table[n][idx]|octet_size }}</td>
33
+            {% else %}
34
+        <td class="number_column">{{ table[n][idx]|number_format }}</td>
35
+            {% endif %}
36
+        {% endif %}
37
+    {% endfor %}
38
+    </tr>
39
+{% endfor %}
40
+    <tr>
41
+        <th>Rank </th>
42
+{% for n in name %}
43
+        <th style="width: 8.5%; padding: 0;"><div class="rot90-container"><div class="rot90">
44
+            {{ n }}
45
+        </div></div></th>
46
+{% endfor %}
47
+    </tr>
48
+</table>

+ 111
- 0
templates/admin/site-info.twig View File

@@ -0,0 +1,111 @@
1
+<style type="text/css">
2
+div#phpinfo {color: #222; font-family: sans-serif; display: none;}
3
+div#phpinfo pre {margin: 0; font-family: monospace;}
4
+div#phpinfo a:link {color: #009; text-decoration: none; background-color: #fff;}
5
+div#phpinfo a:hover {text-decoration: underline;}
6
+div#phpinfo table {border-collapse: collapse; border: 0; width: 934px; box-shadow: 1px 2px 3px #ccc;}
7
+div#phpinfo .center {text-align: center;}
8
+div#phpinfo .center table {margin: 1em auto; text-align: left;}
9
+div#phpinfo .center th {text-align: center !important;}
10
+div#phpinfo td, th {border: 1px solid #666; font-size: 75%; vertical-align: baseline; padding: 4px 5px;}
11
+div#phpinfo h1 {font-size: 150%;}
12
+div#phpinfo h2 {font-size: 125%;}
13
+div#phpinfo .p {text-align: left;}
14
+div#phpinfo .e {background-color: #ccf; width: 300px; font-weight: bold;}
15
+div#phpinfo .h {background-color: #99c; font-weight: bold;}
16
+div#phpinfo .v {background-color: #ddd; max-width: 300px; overflow-x: auto; word-wrap: break-word;}
17
+div#phpinfo .v i {color: #999;}
18
+div#phpinfo img {float: right; border: 0;}
19
+div#phpinfo hr {width: 934px; background-color: #ccc; border: 0; height: 1px;}
20
+</style>
21
+<div class="linkbox">
22
+    <a href="tools.php?action=site_info&amp;mode=userrank" class="brackets">User ranks</a>
23
+</div>
24
+<div class="thin">
25
+    <h3>OS</h3>
26
+    <div class="box pad">
27
+        <span style="width: 70px; display: inline-block">Uptime:</span> {{ uptime.uptime|raw }} <br />
28
+        <span style="width: 70px; display: inline-block">Idle time:</span> {{ uptime.idletime|raw }} <br /><br />
29
+
30
+        <span style="width: 100px; display: inline-block">User:</span> {{ uid }} <br />
31
+        <span style="width: 100px; display: inline-block">Group:</span> {{ euid }} <br />
32
+        <span style="width: 100px; display: inline-block">Effective User:</span> {{ euid }} <br />
33
+        <span style="width: 100px; display: inline-block">Effective Group:</span> {{ euid }} <br />
34
+        <br /><tt>openssl_random_pseudo_bytes()</tt>:&nbsp;
35
+{%- if openssl_strong -%}
36
+            <span style="color:lime;">Strong</span>
37
+{%- else -%}
38
+            <span style="color:orangered;"><b>Weak/broken</span>
39
+{%- endif -%}
40
+    </div>
41
+    <h3>Timestamps</h3>
42
+    <div class="box pad">
43
+        <span style="width: 50px; display: inline-block">PHP:</span> {{ timestamp_php }}<br />
44
+        <span style="width: 50px; display: inline-block">DB:</span> {{ timestamp_db }}
45
+    </div>
46
+
47
+    <h3>PHP</h3>
48
+    <div class="box pad">
49
+        PHP Version: {{ php_version }} <br />
50
+        <a onclick="toggle_display('phpinfo')" href='javascript:void(0)'>Toggle PHP Info</a><br />
51
+        <div id="phpinfo">{{ phpinfo|raw }}</div>
52
+    </div>
53
+
54
+    <h3>Git</h3>
55
+    <div class="box pad">
56
+        <span style="width: 150px; display: inline-block;">Branch:</span> {{ git_branch }}<br />
57
+        <span style="width: 150px; display: inline-block;">Local Hash:</span> {{ git_hash }}<br />
58
+        <span style="width: 150px; display: inline-block;">Remote Hash:</span> {{ git_hash_remote }}
59
+    </div>
60
+
61
+    <h3>Tables lacking a primary key</h3>
62
+    <div class="box pad">
63
+{% if no_pk is empty %}
64
+    <p>All tables have a primary key defined</p>
65
+{% else %}
66
+    <ul class="stats nobullet">
67
+    {% for table in no_pk %}
68
+        <li><a href="/tools.php?action=database_specifics&table={{ table }}">{{ table }}</a></li>
69
+    {% endfor %}
70
+    </ul>
71
+{% endif %}
72
+    </div>
73
+
74
+    <h3>Composer</h3>
75
+    <div class="box pad">
76
+        Composer Version: {{ composer_version }}<br />
77
+        <table>
78
+            <tr class="colhead">
79
+                <td>Package</td>
80
+                <td>Requirement</td>
81
+                <td>Installed</td>
82
+            </tr>
83
+{% for p in package %}
84
+            <tr>
85
+                <td>{{ p.name }}</td>
86
+                <td>{{ p.require }}</td>
87
+                <td>{{ p.installed }}</td>
88
+            </tr>
89
+{% endfor %}
90
+        </table>
91
+    </div>
92
+
93
+    <h3>Phinx</h3>
94
+    <div class="box pad">
95
+        {{ phinx.version }}<br />
96
+        <table>
97
+            <tr class='colhead'>
98
+                <td>Status</td>
99
+                <td>Migration ID</td>
100
+                <td>Migration Name</td>
101
+            </tr>
102
+{% for m in phinx.migration %}
103
+            <tr>
104
+                <td>{{ m.migration_status }}</td>
105
+                <td>{{ m.migration_id }}</td>
106
+                <td>{{ m.migration_name }}</td>
107
+            </tr>
108
+{% endfor %}
109
+        </table>
110
+    </div>
111
+</div>

+ 57
- 0
templates/admin/site-option.twig View File

@@ -0,0 +1,57 @@
1
+<div class="header">
2
+    <h1>Site Options</h1>
3
+</div>
4
+<table width="100%">
5
+    <tr class="colhead">
6
+        <td>Name</td>
7
+        <td>Value</td>
8
+        <td>Comment</td>
9
+{% if is_admin %}
10
+        <td>Manage</td>
11
+{% endif %}
12
+    </tr>
13
+
14
+{% if is_admin %}
15
+    <tr class="rowa">
16
+        <form class="create_form" name="site_option" action="" method="post">
17
+            <td title="Words must be separated by dashes or underscores">
18
+                <input type="text" size="40" name="name" />
19
+            </td>
20
+            <td>
21
+                <input type="text" size="20" name="value" />
22
+            </td>
23
+            <td>
24
+                <input type="text" size="75" name="comment" />
25
+            </td>
26
+            <td>
27
+                <input type="hidden" name="action" value="site_options" />
28
+                <input type="hidden" name="auth" value="{{ auth }}" />
29
+                <input type="submit" name="submit" value="Create" />
30
+            </td>
31
+        </form>
32
+    </tr>
33
+{% endif %}
34
+
35
+{% for opt in list %}
36
+    <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
37
+    {% if is_admin %}
38
+    <form class="manage_form" name="site_option" action="" method="post">
39
+        <td><input type="text" size="40" name="name" value="{{ opt.name }}" /></td>
40
+        <td><input type="text" size="20" name="value" value="{{ opt.value }}" /></td>
41
+        <td><input type="text" size="75" name="comment" value="{{ opt.comment }}" /></td>
42
+        <td>
43
+            <input type="hidden" name="action" value="site_options" />
44
+            <input type="hidden" name="auth" value="{{ auth }}" />
45
+            <input type="hidden" name="id" value="{{ opt.id }}" />
46
+            <input type="submit" name="submit" value="Edit" />
47
+            <input type="submit" name="submit" value="Delete" />
48
+        </td>
49
+    </form>
50
+    {% else %}
51
+        <td>{{ opt.name }}</td>
52
+        <td>{{ opt.value }}</td>
53
+        <td>{{ opt.comment }}</td>
54
+    {% endif %}
55
+    </tr>
56
+{% endfor %}
57
+</table>

+ 27
- 0
templates/admin/staffpm-list.twig View File

@@ -0,0 +1,27 @@
1
+{% for pm in list %}
2
+    {% if loop.first %}
3
+<div class="box" id="staffpms_box">
4
+    <div class="head">
5
+        Staff PMs <a href="#" onclick="$('#staffpms').gtoggle(); return false;" class="brackets">View</a>
6
+    </div>
7
+    <table width="100%" class="message_table hidden" id="staffpms">
8
+        <tr class="colhead">
9
+            <td>Subject</td>
10
+            <td>Date</td>
11
+            <td>Assigned to</td>
12
+            <td>Replies</td>
13
+            <td>Resolved by</td>
14
+        </tr>
15
+    {% endif %}
16
+        <tr>
17
+            <td><a href="staffpm.php?action=viewconv&amp;id={{ pm.id }}">{{ pm.subject }}</a></td>
18
+            <td>{{ pm.date|time_diff(2) }}</td>
19
+            <td>{% if assigned_to_user %}{{ pm.user_id|user_url }}{% else %}{{ pm.reader }}{% endif %}</td>
20
+            <td>{{ pm.replies }}</td>
21
+            <td>{% if pm.resolver_id %}{{ pm.resolver_id|user_url }}{% else %}(unresolved){% endif %}</td>
22
+        </tr>
23
+    {% if loop.last %}
24
+    </table>
25
+</div>
26
+    {% endif %}
27
+{% endfor %}

+ 50
- 0
templates/admin/tracker-info.twig View File

@@ -0,0 +1,50 @@
1
+<div class="thin">
2
+    <div class="header">
3
+        <h2>Tracker info</h2>
4
+    </div>
5
+    <div class="linkbox">
6
+        <a href="?action={{ action }}" class="brackets" />Main stats</a>
7
+    </div>
8
+    <div class="sidebar">
9
+        <div class="box box2">
10
+            <div class="head"><strong>User stats</strong></div>
11
+            <div class="pad">
12
+                <form method="get" action="">
13
+                    <input type="hidden" name="action" value="ocelot_info" />
14
+                    <label for="userid">Get stats for user (id or @username)</label><br /><br />
15
+                    <input type="text" id="userid" name="userid" placeholder="User ID" value="{{ user_id }}" /><br /><br />
16
+                    <input type="submit" value="Go" />
17
+                </form>
18
+            </div>
19
+        </div>
20
+    </div>
21
+    <div class="main_column">
22
+        <div class="box box2">
23
+            <div class="head"><strong>Numbers and such</strong></div>
24
+            <div class="pad">
25
+{% if peer_stats %}
26
+                User ID: {{ user_id }}<br />
27
+                Leeching: {{ peer_stats[0]|number_format }}<br />
28
+                Seeding: {{ peer_stats[1]|number_format }}<br />
29
+{% elseif main_stats %}
30
+    {% for key, value in main_stats %}
31
+                {%- if value == "Uptime:" -%}
32
+                    {{ value }}
33
+                {%- elseif key starts with "bytes " -%}
34
+                    {{ value|octet_size }}
35
+                {%- else -%}
36
+                    {{ value|number_format }}
37
+                {%- endif %}
38
+                {{ key }}<br />
39
+    {% endfor %}
40
+{% elseif announce_key %}
41
+                Failed to get stats for user {{ user_id }}
42
+{% elseif user_id %}
43
+                User {{ user_id }} doesn't exist
44
+{% else %}
45
+                Failed to get tracker info
46
+{% endif %}
47
+            </div>
48
+        </div>
49
+    </div>
50
+</div>

+ 27
- 0
templates/admin/user-custom-permission.twig View File

@@ -0,0 +1,27 @@
1
+<div class="thin">
2
+{% if list is empty %}
3
+    <h2 align="center">There are no users with custom permissions.</h2>
4
+{% else %}
5
+    <table width="100%">
6
+        <tr class="colhead">
7
+            <td>User</td>
8
+            <td>Custom Permissions</td>
9
+            <td>Action</td>
10
+        </tr>
11
+    {% for user_id, permission in list %}
12
+        <tr>
13
+            <td>{{ user_id|user_full }}</td>
14
+            <td>
15
+                <ul class="nobullet">
16
+        {% for name, value in permission %}
17
+                    <li>{{ name }}</li>
18
+        {% endfor %}
19
+                </ul>
20
+            </td>
21
+            <td><a href="user.php?action=permissions&amp;userid={{ user_id }}">Manage</a></td>
22
+        </tr>
23
+    {% endfor %}
24
+    </table>
25
+{% endif %}
26
+</div>
27
+<br />

+ 16
- 0
templates/admin/user-info-email.twig View File

@@ -0,0 +1,16 @@
1
+<tr><th colspan="3">Email History</th></tr>
2
+<tr>
3
+    <th>Address</th>
4
+    <th>Registered since</th>
5
+    <th>Registered from</th>
6
+</tr>
7
+{% for i in info %}
8
+<tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
9
+    <td>{{ i.0 }}</td>
10
+    <td>{{ i.1 }}</td>
11
+    <td>{{ i.2 }}
12
+        <a href="user.php?action=search&amp;ip_history=on&amp;ip={{ i.0 }}" class="brackets tooltip" title="Shared with other users?">S</a>
13
+        <a href="https://whatismyipaddress.com/ip/{{ i.0 }}" class="brackets tooltip" title="Search WIMIA.com">WI</a>
14
+    </td>
15
+</tr>
16
+{% endfor %}

+ 16
- 0
templates/admin/user-info-ipv4.twig View File

@@ -0,0 +1,16 @@
1
+<tr><th colspan="3">{{ title }}</th></tr>
2
+<tr>
3
+    <th>Address IPv4</th>
4
+    <th>First seen</th>
5
+    <th>Last seen</th>
6
+</tr>
7
+{% for i in info %}
8
+<tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
9
+    <td>{{ i.0 }}
10
+        <a href="user.php?action=search&amp;ip_history=on&amp;ip={{ i.0 }}" class="brackets tooltip" title="Shared with other users?">S</a>
11
+        <a href="https://whatismyipaddress.com/ip/{{ i.0 }}" class="brackets tooltip" title="Search WIMIA.com">WI</a>
12
+    </td>
13
+    <td>{{ i.1 }}</td>
14
+    <td>{{ i.2 }}</td>
15
+</tr>
16
+{% endfor %}

+ 33
- 0
templates/admin/userflow.twig View File

@@ -0,0 +1,33 @@
1
+<div class="thin">
2
+{% if show_flow %}
3
+    <div class="box pad center">
4
+        <figure class="highcharts-figure"><div id="user-flow"></div></figure>
5
+    </div>
6
+{% endif %}
7
+    {{ paginator.linkbox|raw }}
8
+    <table width="100%">
9
+        <tr class="colhead">
10
+            <td>Date</td>
11
+            <td>(+) Joined</td>
12
+            <td>(-) Manual</td>
13
+            <td>(-) Ratio</td>
14
+            <td>(-) Inactivity</td>
15
+            <td>(-) Total</td>
16
+            <td>Net Growth</td>
17
+        </tr>
18
+{% for d in details %}
19
+    {% set total_out = d.ratio + d.inactivity + d.manual %}
20
+        <tr class="{{ cycle(['a', 'b'], loop.index0) }}">
21
+            <td>{{ d.date }}</td>
22
+            <td>{{ d.joined|number_format }}</td>
23
+            <td>{{ d.manual|number_format }}</td>
24
+            <td>{{ d.ratio|number_format }}</td>
25
+            <td>{{ d.inactivity|number_format }}</td>
26
+            <td>{{ total_out|number_format }}</td>
27
+            <td>{{ (d.joined - total_out)|number_format }}</td>
28
+        </tr>
29
+{% endfor %}
30
+    </table>
31
+    {{ paginator.linkbox|raw }}
32
+</div>
33
+<?php

+ 86
- 0
templates/applicant/admin.twig View File

@@ -0,0 +1,86 @@
1
+{% from 'macro/form.twig' import checked %}
2
+<div class="thin">
3
+
4
+<div class="linkbox">
5
+    <a href="/apply.php" class="brackets">Apply</a>
6
+    <a href="/apply.php?action=view" class="brackets">Current applications</a>
7
+    <a href="/apply.php?action=view&amp;status=resolved" class="brackets">Resolved applications</a>
8
+</div>
9
+
10
+<h3>Manage roles at {{ constant('SITE_NAME') }}</h3>
11
+
12
+<form method="post" action="/apply.php?action=admin">
13
+
14
+<div class="box">
15
+    <div class="head">Current Roles</div>
16
+    <div class="pad">
17
+{% if saved %}
18
+        <p>The role {{ role.title }} was {{ saved }}.</p>
19
+{% endif %}
20
+{% if not editId %}
21
+    {% for role_id, info in list %}
22
+        {% if loop.first %}
23
+        <table>
24
+        {% endif %}
25
+            <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
26
+                <td>
27
+                    <div class="head">
28
+                        <div style="float: right;">
29
+                            <input style="margin-bottom: 10px;" type="submit" name="edit-{{ role_id }}" value="Edit" />
30
+                        </div>
31
+                        <span style="font-size: medium">{{ info.title }}</span> ({% if info.published %}published{% else %}archived{% endif %})
32
+                        <br />Role created {{ info.created|time_diff }} by {{ info.user_id|user_url }}
33
+                        {% if info.modified != ino.created %}
34
+                            last modified {{ info.modified|time_diff }}
35
+                        {% endif %}
36
+                    </div>
37
+                </td>
38
+            </tr>
39
+            <tr>
40
+                <td><div class="pad">{{ info.description|bb_format }}</div></td>
41
+            </tr>
42
+        {% if loop.last %}
43
+        </table>
44
+        {% endif %}
45
+    {% else %}
46
+        <p>There are no current roles. Create one using the form below.</p>
47
+    {% endfor %}
48
+{% endif %}
49
+    </div>
50
+</div>
51
+
52
+<div class="box">
53
+    <div class="head">{% if edit_id %}Edit{% else %}New{% endif %} Role</div>
54
+    <div class="pad">
55
+
56
+    <table>
57
+        <tr>
58
+            <td class="label">Title</td>
59
+            <td><input type="text" width="100" name="title" value="{% if edit_id %}{{ role.title }}{% endif %}" /></td>
60
+        </tr>
61
+        <tr>
62
+            <td class="label">Visibility</td>
63
+            <td>
64
+                <input type="radio" name="status" value="1" id="status-pub"{{ checked(edit_id and role.isPublished) }} /><label for="status-pub">published</label><br />
65
+                <input type="radio" name="status" value="0" id="status-arch"{{ checked((not edit_id) or role.isArchived) }} /><label for="status-arch">archived</label>
66
+            </td>
67
+        </tr>
68
+        <tr>
69
+            <td class="label">Description</td>
70
+            <td>
71
+{% if edit_id %}
72
+                <input type="hidden" name="edit" value="{{ edit_id }}"/>
73
+{% endif %}
74
+                <input type="hidden" name="user_id" value="{{ user_id }}"/>
75
+                <input type="hidden" name="auth" value="{{ auth }}"/>
76
+                {{ text.emit|raw }}
77
+                <input type="submit" id="submit" value="Save Role"/>
78
+            </td>
79
+        </tr>
80
+    </table>
81
+</div>
82
+</div>
83
+
84
+</form>
85
+
86
+</div>

+ 76
- 0
templates/applicant/apply.twig View File

@@ -0,0 +1,76 @@
1
+{% from 'macro/form.twig' import selected %}
2
+<div class="thin">
3
+    <div class="header">
4
+        <h3>Apply for a role at {{ constant('SITE_NAME') }}</h3>
5
+{% if is_admin or is_applicant %}
6
+        <div class="linkbox">
7
+    {% if is_admin %}
8
+            <a href="/apply.php?action=view" class="brackets">Current applications</a>
9
+            <a href="/apply.php?action=view&amp;status=resolved" class="brackets">Resolved applications</a>
10
+            <a href="/apply.php?action=admin" class="brackets">Manage roles</a>
11
+    {% else %}
12
+            <a href="/apply.php?action=view" class="brackets">View your application</a>
13
+    {% endif %}
14
+        </div>
15
+{% endif %}
16
+    </div>
17
+
18
+{% for role_id, role in list %}
19
+    {% if loop.first %}
20
+    <div class="box">
21
+        <div class="head">Open Roles</div>
22
+        <div class="pad">
23
+            <table>
24
+    {% endif %}
25
+                <tr>
26
+                    <td><div class="head">{{ role.title }}</div></td>
27
+                </tr>
28
+                <tr>
29
+                    <td><div class="pad">{{ role.description|bb_format }}</div></td>
30
+                </tr>
31
+    {% if loop.last %}
32
+            </table>
33
+        </div>
34
+    </div>
35
+    {% endif %}
36
+{% else %}
37
+    <div class="box pad">
38
+    <p>Thanks for your interest in helping {{ constant('SITE_NAME') }}! There are
39
+    no openings at the moment. Keep an eye on the front page
40
+    or the forum for announcements in the future.</p>
41
+    </div>
42
+{% endfor %}
43
+
44
+{% if list %}
45
+    {% if error %}
46
+<div class="important">{{ error }}</div>
47
+    {% endif %}
48
+<form class="send_form" id="applicationform" name="apply" action="/apply.php?action=save" method="post">
49
+    <div class="box">
50
+        <div id="quickpost">
51
+            <div class="head">Your Role at {{ constant('SITE_NAME') }}</div>
52
+            <div class="pad">
53
+                <div>Choose a role from the following list:</div>
54
+                <select name="role">
55
+                    <option value="">---</option>
56
+{% for role in list %}
57
+                    <option value="{{ role.role_id }}"{{ selected(role.title == title) }}>{{ role.title }}</option>
58
+{% endfor %}
59
+                </select>
60
+            </div>
61
+            <div class="head">Your cover letter</div>
62
+            <div class="pad">Give us least 80 characters to convince us!
63
+            {{ body.emit|raw }}
64
+            </div>
65
+        </div>
66
+
67
+        <div class="pad preview_submit">
68
+            <input type="hidden" name="auth" value="{{ auth }}" />
69
+            {{ body.button|raw }}
70
+            <input type="submit" value="Send Application" />
71
+        </div>
72
+    </div>
73
+</form>
74
+{% endif %}
75
+</div>
76
+

+ 136
- 0
templates/applicant/view.twig View File

@@ -0,0 +1,136 @@
1
+<div class="thin">
2
+
3
+<div class="linkbox">
4
+    <a href="/apply.php" class="brackets">Apply</a>
5
+{% if id and not is_staff %}
6
+    <a href="/apply.php?action=view" class="brackets">View your applications</a>
7
+{% endif %}
8
+{% if is_staff %}
9
+    {% if resolved or (id and not resolved) %}
10
+    <a href="/apply.php?action=view" class="brackets">Current applications</a>
11
+    {% endif %}
12
+    {% if not resolved %}
13
+    <a href="/apply.php?action=view&status=resolved" class="brackets">Resolved applications</a>
14
+    {% endif %}
15
+    <a href="/apply.php?action=admin" class="brackets">Manage roles</a>
16
+{% endif %}
17
+</div>
18
+
19
+{% if id %}
20
+<div class="box">
21
+    <div class="head"{% if app.isResolved %} style="font-style: italic;"{% endif %}>{{ app.roleTitle }}
22
+    {% if is_staff %}
23
+        <div style="float: right;">
24
+            <form name="role_resolve" method="POST" action="/apply.php?action=view&amp;id={{ id }}">
25
+                <input type="submit" name="resolve" value="{% if app.isResolved %}Reopen{% else %}Resolve{% endif %}" />
26
+                <input type="hidden" name="id" value="{{ id }}"/>
27
+                <input type="hidden" name="auth" value="{{ auth }}"/>
28
+            </form>
29
+        </div>
30
+        <br />Application received from {{ app.userId|user_full }} received {{ app.created|time_diff }}.
31
+    {% endif %}
32
+    </div>
33
+
34
+    <div class="pad">
35
+        <p>{{ app.body|bb_format }}</p>
36
+    {% if not app.isResolved %}
37
+        <form id="thread_note_reply" name="thread_note_replay" method="POST" action="/apply.php?action=view&amp;id={{ id }}">
38
+    {% endif %}
39
+        <table class="forum_post wrap_overflow box vertical_margin">
40
+    {% for note in app.story(is_staff) %}
41
+            <tr class="colhead_dark">
42
+                <td colspan="2">
43
+                    <div style="float: left; padding-top: 10px;">{{ note.user_id|user_url }} - {{ note.created|time_diff }}</div>
44
+                </td>
45
+            </tr>
46
+            <tr>
47
+                <td colspan="2" style="border: 2px solid
48
+                    {%- if not is_staff -%}
49
+                        #808080
50
+                    {%- else -%}
51
+                        {%- if note.visibility == 'staff' -%}
52
+                            #FF8017
53
+                        {%- else -%}
54
+                            #347235
55
+                        {%- endif -%}
56
+                    {%- endif -%}
57
+                    ;">
58
+                    <div style="margin: 5px 4px 20px 4px">
59
+                        {{ note.body|bb_format }}
60
+                    </div>
61
+        {% if is_staff and not app.isResolved %}
62
+                    <div style="float: right; padding-top: 10px 0; margin-bottom: 6px;">
63
+                        <input type="submit" name="note-delete-{{ note.id }}" value="delete" style="height: 20px; padding: 0 3px;"/>
64
+                    </div>
65
+        {% endif %}
66
+                </td>
67
+            </tr>
68
+    {% endfor %}
69
+    {% if not app.isResolved %}
70
+        {% if is_staff %}
71
+            <tr>
72
+                <td class="label">Visibility</td>
73
+                <td>
74
+                    <div>
75
+                        <input type="radio" name="visibility" value="public" /><label for="public">public <span style="color: #347235">(member will see this reply)</span></label><br />
76
+                        <input type="radio" name="visibility" value="staff" checked /><label for="staff">staff <span style="color: #FF8017">(only staff will see this reply)</span></label><br />
77
+                    </div>
78
+                <td>
79
+            </tr>
80
+        {% endif %}
81
+            <tr>
82
+                <td class="label">Reply</td>
83
+                <td>
84
+                    {{ note.preview|raw }}
85
+                    {{ note.field|raw }}
86
+                </td>
87
+            </tr>
88
+            <tr>
89
+                <td colspan="2">
90
+                    <div style="text-align: center;">
91
+                        <input type="hidden" name="id" value="{{ id }}"/>
92
+                        <input type="hidden" name="auth" value="{{ auth }}"/>
93
+                        {{ note.button|raw }}
94
+                        <input type="submit" id="submit" value="Save" />
95
+                    </div>
96
+                </td>
97
+            </tr>
98
+    {% endif %}
99
+        </table>
100
+        </form>
101
+    </div>
102
+</div>
103
+{% else %}
104
+    <h3>{% if resolved %}Resolved{% else %}Current{% endif %} Applications</h3>
105
+    {% for a in list %}
106
+        {% if loop.first %}
107
+    <table>
108
+        <tr class="colhead">
109
+            <td>Role</td>
110
+            {% if is_staff %}
111
+            <td>Applicant</td>
112
+            {% endif %}
113
+            <td>Date Created</td>
114
+            <td>Comments</td>
115
+            <td>Last comment from</td>
116
+            <td>Last comment added</td>
117
+        </tr>
118
+        {% endif %}
119
+        <tr>
120
+            <td><a href="/apply.php?action=view&amp;id={{ a.ID }}">{{ a.Role }}</a></td>
121
+        {% if is_staff %}
122
+            <td><a href="/user.php?id={{ a.UserID }}">{{ a.Username }}</a></td>
123
+        {% endif %}
124
+            <td>{{ a.Created|time_diff }}</td>
125
+            <td>{{ a.nr_notes|number_format }}</td>
126
+            <td><a href="/user.php?id={{ a.last_UserID }}">{{ a.last_Username }}</a></td>
127
+            <td>{% if a.last_Created %}{{ a.last_Created|time_diff }}{% endif %}</td>
128
+        </tr>
129
+        {% if loop.last %}
130
+    </table>
131
+        {% endif %}
132
+    {% else %}
133
+<div class="box pad">The cupboard is empty. There are no applications to show.</div>
134
+    {% endfor %}
135
+{% endif %}
136
+</div>

+ 39
- 0
templates/artist/similar.twig View File

@@ -0,0 +1,39 @@
1
+<div class="box box_artists">
2
+    <div class="head"><strong>Similar Artists</strong></div>
3
+    <ul class="stats nobullet">
4
+{% if not similar %}
5
+        <li><span style="font-style: italic;">None found</span></li>
6
+{% else %}
7
+    {% for s in similar %}
8
+        <li>
9
+            <span class="tooltip" title="{{ s.Score/100 }}"><a href="artist.php?id={{ s.ArtistID }}" style="float: left; display: block;">{{ s.Name }}</a></span>
10
+            <div style="float: right; display: block; letter-spacing: -1px;">
11
+                <a href="artist.php?action=vote_similar&amp;artistid={{ s.ArtistID }}&amp;similarid={{
12
+                    s.SimilarID }}&amp;way=up" class="tooltip brackets vote_artist_up" title="Vote up this similar artist. Use this when you feel that the two artists are quite similar.">&#x25b2;</a>
13
+                <a href="artist.php?action=vote_similar&amp;artistid={{ s.ArtistID }}&amp;similarid={{
14
+                    s.SimilarID }}&amp;way=down" class="tooltip brackets vote_artist_down" title="Vote down this similar artist. Use this when you feel that the two artists are not all that similar.">&#x25bc;</a>
15
+        {% if admin %}
16
+                <span class="remove remove_artist"><a href="artist.php?action=delete_similar&amp;artistid={{ s.ArtistID }}&amp;similarid={{
17
+                    s.SimilarID }}&amp;auth={{ auth }}" class="tooltip brackets" title="Remove this similar artist">&#x2715;</a></span>
18
+        {% endif %}
19
+            </div>
20
+            <br style="clear: both;" />
21
+        </li>
22
+    {% endfor %}
23
+    </ul>
24
+{% endif %}
25
+</div>
26
+<div class="box box_addartists box_addartists_similar">
27
+    <div class="head"><strong>Add similar artist</strong></div>
28
+    <ul class="nobullet">
29
+        <li>
30
+            <form class="add_form" name="similar_artists" action="artist.php" method="post">
31
+                <input type="hidden" name="action" value="add_similar" />
32
+                <input type="hidden" name="auth" value="{{ auth }}" />
33
+                <input type="hidden" name="artistid" value="{{ artist_id }}" />
34
+                <input type="text" autocomplete="off" id="artistsimilar" name="artistname" size="20"{% if autocomplete %} data-gazelle-autocomplete="true"{% endif %} />
35
+                <input type="submit" value="+" />
36
+            </form>
37
+        </li>
38
+    </ul>
39
+</div>

+ 5
- 0
templates/better/links.twig View File

@@ -0,0 +1,5 @@
1
+<div class="linkbox">
2
+    <a class="brackets" href="better.php?method=transcode">Transcodes</a>
3
+    <a class="brackets" href="better.php?method=missing">Missing</a>
4
+    <a class="brackets" href="better.php?method=single">Single Seeded</a>
5
+</div>

+ 69
- 0
templates/better/missing.twig View File

@@ -0,0 +1,69 @@
1
+<br />
2
+<div class="thin">
3
+    <h2>Missing</h2>
4
+    {% include 'better/links.twig' only %}
5
+    <form class="search_form" name="missing" action="" method="get">
6
+        <input type="hidden" name="method" value="missing" />
7
+        <table cellpadding="6" cellspacing="1" border="0" class="border" width="100%">
8
+            <tr>
9
+                <td class="label"><strong>Filter</strong></td>
10
+                <td>
11
+                    <select name="type">
12
+                        <option value="checksum"{{ types.checksum | selected }}>Missing Checksums</option>
13
+                        <option value="tags"{{ types.tags | selected }}>Bad Tags</option>
14
+                        <option value="folders"{{ types.folders | selected }}>Bad Folders</option>
15
+                        <option value="files"{{ types.files | selected }}>Bad Files</option>
16
+                        <option value="lineage"{{ types.lineage | selected }}>Missing Lineage</option>
17
+                        <option value="artwork"{{ types.artwork | selected }}>Missing Artwork</option>
18
+                        <option value="artistimg"{{ types.artistimg | selected }}>Missing Artist Images</option>
19
+                        <option value="artistcollage"{{ types.artistcollage | selected }}>Missing Artists Images in Artist Collages</option>
20
+                        <option value="artistdesc"{{ types.artistdesc | selected }}>Missing Artist Descriptions</option>
21
+                        <option value="artistdiscogs"{{ types.artistdiscogs | selected }}>Missing Artist Discogs ID</option>
22
+                    </select>
23
+                    <select name="filter">
24
+                        <option value="all"{{ filters.all | selected }}>All</option>
25
+                        <option value="snatched"{{ filters.snatched | selected }}>Snatched</option>
26
+                        <option value="uploaded"{{ filters.uploaded | selected }}>Uploaded</option>
27
+                    </select>
28
+                </td>
29
+            </tr>
30
+            <tr>
31
+                <td class="label"><strong>Search</strong></td>
32
+                <td>
33
+                    <input type="search" name="search" size="60" value="{{ search }}" />
34
+                </td>
35
+            </tr>
36
+            <tr><td>&nbsp;</td><td><input type="submit" value="Search" /></td></tr>
37
+        </table>
38
+    </form>
39
+    {{ paginator.linkbox|raw }}
40
+    <div class="box pad">
41
+        <div class="torrent">
42
+            <h3>There are {{ result_count }} {{ mode }} remaining
43
+                {% if mode == 'torrents' and result_count > 1 and perms.zip_downloader %}
44
+                    {% include 'better/zip.twig' with {torrent_ids: torrent_ids} only %}
45
+                {% endif %}
46
+            </h3>
47
+        </div>
48
+        {% if mode is same as('torrents') %}
49
+            {% include 'better/torrents.twig' with {results: results, auth_key: auth_key, torrent_pass: torrent_pass, tokens: tokens} only %}
50
+        {% elseif mode is same as('groups') %}
51
+            <table width"=100%" class="torrent_table">
52
+                {% for id, group in results %}
53
+                    <tr>
54
+                        <td><a href="torrents.php?groupid={{ id }}&amp;action=editgroup">[Edit]</a>&nbsp;&nbsp;{{ group.artist|raw }} - <a href="torrents.php?id={{ id }}" target="_blank">{{ group.name|raw }}</a></td>
55
+                    </tr>
56
+                {% endfor %}
57
+            </table>
58
+        {% else %}
59
+            <table width"=100%" class="torrent_table">
60
+                {% for id, name in results %}
61
+                    <tr>
62
+                        <td><a href="artist.php?artistid={{ id }}&amp;action=edit">[Edit]</a>&nbsp;&nbsp;<a href="artist.php?id={{ id }}">{{ name|raw }}</a></td>
63
+                    </tr>
64
+                {% endfor %}
65
+            </table>
66
+        {% endif %}
67
+    </div>
68
+    {{ paginator.linkbox|raw }}
69
+</div>

+ 16
- 0
templates/better/single.twig View File

@@ -0,0 +1,16 @@
1
+<br />
2
+<div class="thin">
3
+    <h2>Single Seeded</h2>
4
+    {% include 'better/links.twig' only %}
5
+    <div class="box pad">
6
+        <div class="torrent">
7
+            <h3>Here are {{ result_count }} random torrents
8
+                {% if result_count > 0 and perms.zip_downloader %}
9
+                    {% include 'better/zip.twig' with {torrent_ids: torrent_ids} only %}
10
+                {% endif %}
11
+            </h3>
12
+        </div>
13
+        {% include 'better/torrents.twig' with {results: results, auth_key: auth_key, torrent_pass: torrent_pass, tokens: tokens} only %}
14
+    </div>
15
+</div>
16
+

+ 20
- 0
templates/better/torrents.twig View File

@@ -0,0 +1,20 @@
1
+<table width"=100%" class="torrent_table">
2
+    {% for id, row in results %}
3
+        <tr class="torrent torrent_row{{ row.snatched ? ' snatched_torrent' : '' }}">
4
+            <td>
5
+                <span class="torrent_links_block">
6
+                    <a href="torrents.php?action=download&amp;id={{ id }}&amp;authkey={{ auth_key }}&amp;torrent_pass={{ torrent_pass }}" class="brackets tooltip" title="Download">DL</a>
7
+                    {% if row.token %}
8
+                        | <a href="torrents.php?action=download&amp;id={{ id }}&amp;authkey={{ auth_key }}&amp;torrent_pass={{ torrent_pass }}&amp;usetoken=1" class="brackets tooltip" title="Use a FL Token" onclick="return confirm('{{ row.fl_message }}');">FL</a>
9
+                    {% endif %}
10
+                </span>
11
+                {{ row.name | raw }}
12
+                {% if perms.admin_reports %}
13
+                    <a href="better.php?method=missing&amp;type={{ type }}&amp;remove={{ id }}&amp;filter={{ filter }}&amp;search={{ search }}" class="brackets">X</a>
14
+                {% endif %}
15
+                <div class="tags">{{ row.tags | raw }}</div>
16
+        </td>
17
+    </tr>
18
+    {% endfor %}
19
+</table>
20
+

+ 4
- 0
templates/better/zip.twig View File

@@ -0,0 +1,4 @@
1
+<span class="torrents_links_block">
2
+    <a class="brackets" href="torrents.php?action=collector&amp;title=better&amp;ids={{ torrent_ids }}" onclick="return confirm('If you do not have the content, your ratio WILL be affected; be sure to check the size of all torrents before downloading.');">Download All</a>
3
+</span>
4
+

+ 31
- 0
templates/bonus/bonus-pool.twig View File

@@ -0,0 +1,31 @@
1
+<div class="thin">
2
+    <div class="box pad">
3
+        <h3>The <b>{{ pool.name }}</b> pool is open for business!</h3>
4
+        <div>Donate points for greater good! The points you give here will be distributed out to everyone
5
+        who participates in the contest. You can give as many times as you want until the end.</div>
6
+        <br />
7
+        <h3>The grand total currently stands at {{ pool.total|number_format }} points</h3>
8
+        <form class="pool_form" name="pool" id="poolform" action="bonus.php?action=donate" method="post">
9
+            <table>
10
+                <thead>
11
+                    <tr><th>Current BP</th><th>Donated BP</th></tr>
12
+                <thead>
13
+                <tbody>
14
+                    <tr>
15
+                        <td>{{ points|number_format }}</td>
16
+                        <td><input type="text" width="10" name="donate" />
17
+                            <input type="hidden" name="poolid" value="{{ pool.bonus_pool_id }}"/>
18
+                            <input type="hidden" name="userid" value="{{ user_id }}"/>
19
+                            <input type="hidden" name="auth" value="{{ auth }}"/>
20
+                        </td>
21
+                    </tr>
22
+                    <tr>
23
+                        <td></td>
24
+                        <td><input type="submit" value="Donate" /></td>
25
+                    </tr>
26
+                </tbody>
27
+            </table>
28
+            <div><small>The fine print: obviously, you cannot donate more BP than you currently have. There are no refunds. Some handling fees apply.</small></div>
29
+        </form>
30
+    </div>
31
+</div>

+ 43
- 0
templates/bonus/store.twig View File

@@ -0,0 +1,43 @@
1
+{% for item in list %}
2
+{% if loop.first %}
3
+<div class="thin">
4
+    {% if discount %}
5
+    <h3 style="text-align: center; color: lime;">All prices currently {{ min(100, max(0, discount)) }}% off &mdash; Hurry, sale ends soon &mdash; While stocks last!</h3>
6
+    {% endif %}
7
+    {% if admin %}
8
+    <div class="pad box">
9
+        <div class="thin">NB: Bonus Shop discounts are set in the <a href="/tools.php?action=site_options">Site Options</a>.</div>
10
+    </div>
11
+    {% endif %}
12
+    <table>
13
+        <thead>
14
+            <tr class="colhead">
15
+                <td>Description</td>
16
+                <td width="60px">Points</td>
17
+                <td width="120px">Checkout</td>
18
+            </tr>
19
+        </thead>
20
+        <tbody>
21
+{% endif %}
22
+{% if item.MinClass <= class %}
23
+            <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
24
+                <td>{{ item.Title }}</td>
25
+                <td style="text-align:right">{{ item.Price|number_format }}</td>
26
+                <td>
27
+    {% if points >= item.Price %}
28
+                    <a id="bonusconfirm" href="bonus.php?action=purchase&amp;label={{ item.Label
29
+                        }}&amp;auth={{ auth }}" onclick="{{ item.JS_on_click }}(event, '{{ item.Title }}', {{ item.JS_next_function }}, this);">Purchase</a>
30
+    {% else %}
31
+                    <span style="font-style: italic">Too Expensive</span>
32
+
33
+    {% endif %}
34
+{% endif %}
35
+                </td>
36
+    </tr>
37
+{% if loop.last %}
38
+        </tbody>
39
+    </table>
40
+    <br />
41
+</div>
42
+{% endif %}
43
+{% endfor %}

+ 8
- 0
templates/bonus/token-other.twig View File

@@ -0,0 +1,8 @@
1
+Hello {{ TO }},
2
+
3
+[user]{{ FROM }}[/user] has sent you {{ AMOUNT }} freeleech token{{ PLURAL }} to use!
4
+You can use tokens to download torrents without being charged any download.
5
+
6
+More details about FL tokens can be found on [url={{ SITE_URL }}/wiki.php?action=article&amp;id={{ WIKI_ID }}]the wiki[/url].
7
+
8
+Enjoy!

+ 13
- 0
templates/bookmark/body.twig View File

@@ -0,0 +1,13 @@
1
+{% for b in list %}
2
+<tr class="drag row{{ cycle(['a', 'b'], loop.index0) }}" id="li_{{ b.group_id }}">
3
+    <td>
4
+        <input class="sort_numbers" type="text" name="sort[{{ b.group_id }}]" value="{{ b.sequence }}" id="sort_{{ b.group_id }}" size="4" />
5
+    </td>
6
+    <td>{{ loop.index }}</td>
7
+    <td>{{ b.year }}</td>
8
+    <td>{{ b.artist|raw }}{% if showcase %} [<abbr class="tooltip" title="This is a Vanity House release">VH</abbr>]{% endif %}</td>
9
+    <td><a href="torrents.php?id={{ b.group_id }}" class="tooltip" title="View torrent">{{ b.name }}</a></td>
10
+    <td class="nobr tooltip" title="{{ b.added }}">{{ b.added|time_diff }}</td>
11
+    <td class="center"><input type="checkbox" name="remove[{{ b.group_id }}]" value="" /></td>
12
+</tr>
13
+{% endfor %}

+ 13
- 0
templates/bookmark/footer.twig View File

@@ -0,0 +1,13 @@
1
+            </tbody>
2
+        </table>
3
+        <div class="drag_drop_save">
4
+            <input type="submit" name="update" value="Update ranking" title="Save your rank" class="tooltip save_sortable_collage" />
5
+            <input type="submit" name="delete" value="Delete checked" title="Remove items" class="tooltip save_sortable_collage" />
6
+        </div>
7
+        <div>
8
+            <input type="hidden" name="action" value="mass_edit" />
9
+            <input type="hidden" name="type" value="{{ edit_type }}" />
10
+            <input type="hidden" name="auth" value="{{ auth }}" />
11
+        </div>
12
+    </form>
13
+</div>

+ 35
- 0
templates/bookmark/header.twig View File

@@ -0,0 +1,35 @@
1
+<div class="thin">
2
+    <div class="header">
3
+        <h2>{{ heading }}</h2>
4
+    </div>
5
+    <table width="100%" class="layout">
6
+        <tr class="colhead"><td id="sorting_head">Sorting</td></tr>
7
+        <tr>
8
+            <td id="drag_drop_textnote">
9
+            <ul>
10
+                <li>Click on the headings to organize columns automatically.</li>
11
+                <li>Sort multiple columns simultaneously by holding down the shift key and clicking other column headers.</li>
12
+                <li>Click and drag any row to change its order.</li>
13
+                <li>Double-click on a row to check it.</li>
14
+            </ul>
15
+            </td>
16
+        </tr>
17
+    </table>
18
+    <form action="bookmarks.php" method="post" id="drag_drop_collage_form">
19
+        <div class="drag_drop_save">
20
+            <input type="submit" name="update" value="Update ranking" title="Save your rank" class="tooltip save_sortable_collage" />
21
+            <input type="submit" name="delete" value="Delete checked" title="Remove items" class="tooltip save_sortable_collage" />
22
+        </div>
23
+        <table id="manage_collage_table">
24
+            <thead>
25
+                <tr class="colhead">
26
+                    <th style="width: 7%;" data-sorter="false">Order</th>
27
+                    <th style="width: 1%;"><span><abbr class="tooltip" title="Current order">#</abbr></span></th>
28
+                    <th style="width: 1%;"><span>Year</span></th>
29
+                    <th style="width: 15%;" data-sorter="ignoreArticles"><span>Artist</span></th>
30
+                    <th data-sorter="ignoreArticles"><span>Torrent</span></th>
31
+                    <th style="width: 5%;" data-sorter="relativeTime"><span>Bookmarked</span></th>
32
+                    <th style="width: 1%;" id="check_all" data-sorter="false"><span>Remove</span></th>
33
+                </tr>
34
+            </thead>
35
+            <tbody>

+ 8
- 0
templates/bookmark/none.twig View File

@@ -0,0 +1,8 @@
1
+<div class="thin">
2
+    <div class="header">
3
+        <h2>No torrents found.</h2>
4
+    </div>
5
+    <div class="box pad" align="center">
6
+        <p>Add some torrents and come back later.</p>
7
+    </div>
8
+</div>

+ 26
- 0
templates/collage/delete.twig View File

@@ -0,0 +1,26 @@
1
+<div class="thin center">
2
+    <div class="box" style="width: 600px; margin: 0px auto;">
3
+        <div class="head colhead">
4
+            Delete collage
5
+        </div>
6
+        <div class="pad">
7
+            <form class="delete_form" name="collage" action="collages.php" method="post">
8
+                <input type="hidden" name="action" value="take_delete" />
9
+                <input type="hidden" name="auth" value="{{ auth }}" />
10
+                <input type="hidden" name="collageid" value="{{ id }}" />
11
+{% if is_personal %}
12
+                <div class="alertbar" style="margin-bottom: 1em;">
13
+                    <strong>Warning: This is a personal collage. If you delete this collage, it <em>cannot</em> be recovered!</strong>
14
+                </div>
15
+{% endif %}
16
+                <div class="field_div">
17
+                    <strong>Reason: </strong>
18
+                    <input type="text" name="reason" size="40" />
19
+                </div>
20
+                <div class="submit_div">
21
+                    <input value="Delete" type="submit" />
22
+                </div>
23
+            </form>
24
+        </div>
25
+    </div>
26
+</div>

+ 46
- 0
templates/collage/description.twig View File

@@ -0,0 +1,46 @@
1
+<ul>
2
+<li><strong>Personal</strong> – You can put whatever you want here.
3
+If you do not see the option then you must a slot in the <a
4
+href="/bonus.php">Bonus Shop</a>. Note that Donors are given up to
5
+five free personal collages.</li>
6
+
7
+<li><strong>Theme</strong> – A collage containing releases that all
8
+relate to a certain theme.<br />Examples: "Concept Albums", "Funky
9
+Groove", "Predominantly Polka Dot Covers"). <b>DO NOT</b> use this
10
+category for personal collages. You may lose your collage creation
11
+privileges.</li>
12
+
13
+<li><strong>Genre Introduction</strong> – A subjective introduction
14
+to a genre composed by our own users.</li>
15
+
16
+<li><strong>Discography</strong> – A collage containing all the
17
+releases of an artist, used for keeping track of side projects.</li>
18
+
19
+<li><strong>Label</strong> – A collage containing all the releases
20
+of a particular record label.</li>
21
+
22
+<li><strong>Staff Picks</strong> – A listing of recommendations
23
+picked by the staff on special occasions.</li>
24
+
25
+<li><strong>Artists</strong> – A collection of artists who are
26
+related in some way, for example <i>The World's Greatest Orchestras
27
+according to Gramophone magazine</i> or <i>Musicians who passed
28
+away in 2020</i>.</li>
29
+
30
+<li><strong>Charts</strong> – A collage of all the releases that
31
+comprise a certain type of chart<br /> Examples: Billboard Top 100,
32
+Pitchfork Top 100, {{ constant('SITE_NAME') }} Top 10, etc.).</li>
33
+
34
+<li><strong>Awards</strong> – A collage of the releases in an annual
35
+competition, with winners determined by member voting or panel
36
+decision<br /> Examples: The Grammy Awards, Gramophone Classical
37
+Music Awards, Academy Awards.</li>
38
+
39
+<li><strong>Series</strong> – A defined project within an established
40
+label or accross two or more established labels, must have a specific
41
+series Title and often have a series Logo; can be original releases
42
+or reissues.<br /> Examples: The Desert Sessions (across the following
43
+labels – Matador,Rekords, Man's Ruin, Southern Lord, Ipecac) and
44
+The Originals (Deutsche Gramophone and Decca; The Vivaldi Edition
45
+(Naive / Opus111 labels)</li>
46
+</ul>

+ 30
- 0
templates/collage/header.twig View File

@@ -0,0 +1,30 @@
1
+<div class="header">
2
+    <h2>{{ name }}</h2>
3
+    <div class="linkbox">
4
+        <a href="collages.php" class="brackets">List of collages</a>
5
+{% if can_create %}
6
+        <a href="collages.php?action=new" class="brackets">New collage</a>
7
+{% endif %}
8
+        <br /><br />
9
+{% if can_sub %}
10
+        <a href="#" id="subscribelink{{ id }}" class="brackets" onclick="CollageSubscribe({{ id }}); return false;">{{ subbed ? 'Unsubscribe' : 'Subscribe' }}</a>
11
+{% endif %}
12
+{% if can_edit %}
13
+        <a href="collages.php?action=edit&amp;collageid={{ id }}" class="brackets">Edit description</a>
14
+{% else %}
15
+        <span class="brackets">Locked</span>
16
+{% endif %}
17
+{% if bookmarked %}
18
+        <a href="#" id="bookmarklink_collage_{{ id }}" class="brackets" onclick="Unbookmark('collage', {{ id }}, 'Bookmark'); return false;">Remove bookmark</a>
19
+{% else %}
20
+        <a href="#" id="bookmarklink_collage_{{ id }}" class="brackets" onclick="Bookmark('collage', {{ id }}, 'Remove bookmark'); return false;">Bookmark</a>
21
+{% endif %}
22
+{% if can_manage %}
23
+        <a href="collages.php?action={{ object == 'torrent' ? 'manage' : 'manage_artists' }}&amp;collageid={{ id }}" class="brackets">Manage {{ object }}s</a>
24
+{% endif %}
25
+        <a href="reports.php?action=report&amp;type=collage&amp;id={{ id }}" class="brackets">Report collage</a>
26
+{% if can_delete %}
27
+        <a href="collages.php?action=delete&amp;collageid={{ id }}" class="brackets">Delete</a>
28
+{% endif %}
29
+    </div>
30
+</div>

+ 24
- 0
templates/collage/recover.twig View File

@@ -0,0 +1,24 @@
1
+<div class="thin center">
2
+    <div class="box" style="width: 600px; margin: 0px auto;">
3
+        <div class="head colhead">
4
+            Recover deleted collage
5
+        </div>
6
+        <div class="pad">
7
+            <form class="undelete_form" name="collage" action="collages.php" method="post">
8
+                <input type="hidden" name="action" value="recover" />
9
+                <input type="hidden" name="auth" value="{{ auth }}" />
10
+                <div class="field_div">
11
+                    <strong>Collage ID: </strong>
12
+                    <input type="text" name="id" size="8" />
13
+                </div>
14
+                <div class="field_div">
15
+                    <strong>Collage name: </strong>
16
+                    <input type="text" name="name" size="40" />
17
+                </div>
18
+                <div class="submit_div">
19
+                    <input value="Recover!" type="submit" />
20
+                </div>
21
+            </form>
22
+        </div>
23
+    </div>
24
+</div>

+ 131
- 0
templates/collage/sidebar.twig View File

@@ -0,0 +1,131 @@
1
+<div class="box box_category">
2
+    <div class="head"><strong>Category</strong></div>
3
+    <div class="pad">
4
+    <a href="collages.php?action=search&amp;cats[{{ category_id }}]=1">{{ category_name }}</a>
5
+{% if is_personal %}
6
+collage by {{ user_id|user_url }}
7
+{% endif %}
8
+    </div>
9
+</div>
10
+<div class="box box_description">
11
+    <div class="head"><strong>Description</strong></div>
12
+    <div class="pad">{{ description|raw }}</div>
13
+</div>
14
+<div class="box box_info box_statistics_collage_{{ object }}s">
15
+    <div class="head"><strong>Statistics</strong></div>
16
+    <ul class="stats nobullet">
17
+        <li>Entries: {{ entries|number_format }}</li>
18
+{% if artists %}
19
+        <li>Artists: {{ artists|number_format }}</li>
20
+{% endif %}
21
+        <li>Subscribers: {{ subscribers|number_format }}</li>
22
+        <li>Built by {{ contributors_n|number_format }} user{{ contributors_n|plural }}</li>
23
+        <li>Last updated: {{ updated|time_diff }}</li>
24
+    </ul>
25
+</div>
26
+{% if top_tags is defined %}
27
+<div class="box box_tags">
28
+    <div class="head"><strong>Top Tags</strong></div>
29
+    <div class="pad">
30
+{%   if top_tags is empty %}
31
+        <i>None yet</i>
32
+{%   else %}
33
+        <ol style="padding-left: 5px;">
34
+{% for t in top_tags %}
35
+            <li><a href="collages.php?action=search&amp;tags={{ t.tag }}">{{ t.tag }}</a> ({{ t.count }})</li>
36
+{% endfor %}
37
+        </ol>
38
+{%     endif %}
39
+    </div>
40
+</div>
41
+{% endif %}
42
+{% if artists %}
43
+<div class="box box_artists">
44
+    <div class="head"><strong>Top Artists</strong></div>
45
+    <div class="pad">
46
+        <ol style="padding-left: 5px;">
47
+{% for artist in top_artists %}
48
+            <li><a href="artist.php?id={{ artist.id }} ">{{ artist.name }}</a> ({{ artist.count|number_format }})</li>
49
+{% endfor %}
50
+        </ol>
51
+    </div>
52
+</div>
53
+{% endif %}
54
+{% if not is_personal %}
55
+<div class="box box_contributors">
56
+    <div class="head"><strong>Top Contributors</strong></div>
57
+    <div class="pad">
58
+        <ol style="padding-left: 5px;">
59
+{% for user_id, additions in contributors %}
60
+            <li>{{ user_id|user_url }} ({{ additions|number_format }})</li>
61
+{% endfor %}
62
+        </ol>
63
+    </div>
64
+</div>
65
+{% endif %}
66
+{% if can_add %}
67
+<div class="box box_add{{ object }}">
68
+    <div class="head"><strong>Add {{ object_name }}</strong><span class="float_right"><a href="#" onclick="$('.add_{{ object }}_container').toggle_class('hidden'); this.innerHTML = (this.innerHTML == 'Batch add' ? 'Individual add' : 'Batch add'); return false;" class="brackets">Batch add</a></span></div>
69
+    <div class="pad add_{{ object }}_container">
70
+        <form class="add_form" name="{{ object }}" action="collages.php" method="post">
71
+            <input type="hidden" name="action" value="add_{{ object }}" />
72
+            <input type="hidden" name="auth" value="{{ auth }}" />
73
+            <input type="hidden" name="collageid" value="{{ id }}" />
74
+            <div class="field_div">
75
+                <input type="text" size="20" name="url" />
76
+            </div>
77
+            <div class="submit_div">
78
+                <input type="submit" value="Add" />
79
+            </div>
80
+            <span style="font-style: italic;">Enter the URL of {{ object|article }} {{ object }} on the site.</span>
81
+        </form>
82
+    </div>
83
+    <div class="pad hidden add_{{ object }}_container">
84
+        <form class="add_form" name="{{ object }}s" action="collages.php" method="post">
85
+            <input type="hidden" name="action" value="add_{{ object }}_batch" />
86
+            <input type="hidden" name="auth" value="{{ auth }}" />
87
+            <input type="hidden" name="collageid" value="{{ id }}" />
88
+            <div class="field_div">
89
+                <textarea name="urls" rows="5" cols="25" style="white-space: pre; word-wrap: normal; overflow: auto;"></textarea>
90
+            </div>
91
+            <div class="submit_div">
92
+                <input type="submit" value="Add" />
93
+            </div>
94
+            <span style="font-style: italic;">Enter the URLs of {{ object}}s on the site, one per line.</span>
95
+        </form>
96
+    </div>
97
+</div>
98
+{% endif %}
99
+<h3>Comments</h3>
100
+{% for comment in comments %}
101
+<div class="box comment">
102
+    <div class="head">
103
+        {{ comment.author_id|user_url }} {{ comment.added|time_diff }}
104
+        <br />
105
+        <a href="reports.php?action=report&amp;type=collages_comment&amp;id={{ comment.id }}" class="brackets">Report</a>
106
+    </div>
107
+    <div class="pad">{{ comment.body|raw }}</div>
108
+</div>
109
+{% endfor %}
110
+<div class="box pad">
111
+    <a href="collages.php?action=comments&amp;collageid={{ id }}" class="brackets">View all comments</a>
112
+</div>
113
+{% if can_post %}
114
+<div class="box box_addcomment">
115
+    <div class="head"><strong>Add comment</strong></div>
116
+    <form class="send_form" name="comment" id="quickpostform" onsubmit="quickpostform.submit_button.disabled = true;" action="comments.php" method="post">
117
+        <input type="hidden" name="action" value="take_post" />
118
+        <input type="hidden" name="page" value="collages" />
119
+        <input type="hidden" name="auth" value="{{ auth }}" />
120
+        <input type="hidden" name="pageid" value="{{ id }}" />
121
+        <div class="pad">
122
+            <div class="field_div">
123
+                <textarea name="body" cols="24" rows="5"></textarea>
124
+            </div>
125
+            <div class="submit_div">
126
+                <input type="submit" id="submit_button" value="Add comment" />
127
+            </div>
128
+        </div>
129
+    </form>
130
+</div>
131
+{% endif %}

+ 27
- 0
templates/collector.twig View File

@@ -0,0 +1,27 @@
1
+{{ constant('SITE_NAME') }} Collector Summary for {{ title }}
2
+
3
+User:     {{ user.username }}
4
+Passkey:  {{ user.announceKey }}
5
+Announce: {{ user.announceUrl }}
6
+
7
+Torrent groups scanned: {{ total }}
8
+Torrents included:      {{ added }}
9
+Torrent groups skipped: {{ skipped|length }}
10
+
11
+Total size of torrents: {{ size|octet_size }}
12
+Your buffer:            {{ user.buffer[1]|octet_size }}
13
+To download this collection as freeleech, you will need {{ tokens|number_format }} token{{ tokens|plural }}.
14
+
15
+{% if error %}
16
+Some torrents could not be added to the archive. See ERRORS.txt for details.
17
+{% endif %}
18
+{% if skipped %}
19
+Albums unavailable given your criteria (consider making a request for your desired format)
20
+    {% for file in skipped %}
21
+        {{- file }}
22
+    {% endfor %}
23
+{% endif %}
24
+
25
+Date: {{ date }}
26
+Used: {{ used|octet_size }}
27
+CPU:  {{ time|number_format(2) }} ms

+ 57
- 0
templates/comment/comment.twig View File

@@ -0,0 +1,57 @@
1
+<table class="forum_post box vertical_margin{{ show_avatar ? '' : ' noavatar' }}{{ unread ? ' forum_unread' : ''}}" id="post{{ id }}">
2
+    <colgroup>
3
+{% if show_avatar %}
4
+        <col class="col_avatar" />
5
+{% endif %}
6
+        <col class="col_post_body" />
7
+    </colgroup>
8
+    <tr class="colhead_dark">
9
+        <td colspan="{{ show_avatar ? 2 : 1 }}">
10
+            <div style="float: left;"><a class="post_id" href="{{ url }}">#{{ id }}</a>
11
+                <strong>{{ author.id|user_full }}</strong> {{ added_time|time_diff }} {{ heading|raw }}
12
+                <span id="postcontrol-{{ id }}">
13
+                - <a href="#quickpost" onclick="Quote('{{ id }}','{{ author.username }}', true);" class="brackets">Quote</a>
14
+{%    if show_edit %}
15
+                - <a href="#post{{ id }}" onclick="Edit_Form('{{ id }}','{{ key }}');" class="brackets">Edit</a>
16
+{%    endif %}
17
+                </span>
18
+            </div>
19
+            <div id="bar{{ id }}" style="float: right;">
20
+                <a href="reports.php?action=report&amp;type=comment&amp;id={{ id }}" class="brackets">Report</a>
21
+{% if is_admin %}
22
+{%    if show_delete %}
23
+                - <a href="#post{{ id }}" onclick="Delete('{{ id }}');" class="brackets">Delete</a>
24
+{%    endif %}
25
+{%    if show_warn %}
26
+                <form class="manage_form hidden" name="user" id="warn{{ id }}" action="comments.php" method="post">
27
+                    <input type="hidden" name="action" value="warn" />
28
+                    <input type="hidden" name="postid" value="{{ id }}" />
29
+                </form>
30
+                - <a href="#" onclick="$('#warn{{ id }}').raw().submit(); return false;" class="brackets">Warn</a>
31
+{%     endif %}
32
+                &nbsp;
33
+                <a href="#">&uarr;</a>
34
+{% endif %}
35
+            </div>
36
+        </td>
37
+    </tr>
38
+    <tr>
39
+{% if show_avatar %}
40
+        <td class="avatar" valign="top">{{ avatar|raw }}</td>
41
+{% endif %}
42
+        <td class="body" valign="top">
43
+            <div id="content{{ id }}">
44
+                {{ body|bb_format }}
45
+{% if editor %}
46
+                <br />
47
+                <br />
48
+                <span class="last_edited">
49
+{%    if is_admin %}
50
+                <a href="#content{{ id }}" onclick="LoadEdit('{{ page }}', {{ id }}, 1); return false;">&laquo;</a>
51
+{%    endif %}
52
+                Last edited by {{ editor.id|user_url }} {{ edit_time|time_diff }}</span>
53
+{% endif %}
54
+            </div>
55
+        </td>
56
+    </tr>
57
+</table>

+ 45
- 0
templates/comment/warn.twig View File

@@ -0,0 +1,45 @@
1
+<div class="thin">
2
+    <div class="header">
3
+        <h2>Warning <a href="user.php?id={{ user.id }}">{{ user.username }}</a></h2>
4
+    </div>
5
+    <div class="thin box pad">
6
+        <form class="create_form" name="warning" action="" onsubmit="quickpostform.submit_button.disabled=true;" method="post">
7
+            <input type="hidden" name="postid" value="{{ post_id }}" />
8
+            <input type="hidden" name="action" value="take_warn" />
9
+            <table class="layout" align="center">
10
+                <tr>
11
+                    <td class="label">Reason:</td>
12
+                    <td>
13
+                        <input type="text" name="reason" size="30" />
14
+                    </td>
15
+                </tr>
16
+                <tr>
17
+                    <td class="label">Length:</td>
18
+                    <td>
19
+                        <select name="length">
20
+                            <option value="verbal">Verbal</option>
21
+                            <option value="1">1 week</option>
22
+                            <option value="2">2 weeks</option>
23
+                            <option value="4">4 weeks</option>
24
+                            <option value="8">8 weeks</option>
25
+                        </select>
26
+                    </td>
27
+                </tr>
28
+                <tr>
29
+                    <td class="label">Private message:</td>
30
+                    <td>
31
+                        <textarea id="message" style="width: 95%;" tabindex="1" onkeyup="resize('message');" name="privatemessage" cols="90" rows="4"></textarea>
32
+                    </td>
33
+                </tr>
34
+                <tr>
35
+                    <td class="label">Edit post:</td>
36
+                    <td>
37
+                        <textarea id="body" style="width: 95%;" tabindex="1" onkeyup="resize('body');" name="body" cols="90" rows="8">{{ body }}</textarea>
38
+                        <br />
39
+                        <input type="submit" id="submit_button" value="Warn user" tabindex="1" />
40
+                    </td>
41
+                </tr>
42
+            </table>
43
+        </form>
44
+    </div>
45
+</div>

+ 137
- 0
templates/contest/admin-form.twig View File

@@ -0,0 +1,137 @@
1
+<form class="edit_form" name="contest" id="contestform" action="{{ action }}" method="post">
2
+{% if contest.hasBonusPool %}
3
+<div class="box pad">
4
+    <table>
5
+        <tr><th>Payout</th><th>Value</th></tr>
6
+        <tr>
7
+            <td>Enabled users</td>
8
+            <td>{{ user_count|number_format }}</td>
9
+        </tr>
10
+        <tr>
11
+            <td>Enabled user bonus</td>
12
+            <td>{{ contest.bonusPerUser|number_format(2) }}</td>
13
+        </tr>
14
+        <tr>
15
+            <td>Contest participation</td>
16
+            <td>{{ contest.bonusPerContest|number_format(2) }}</td>
17
+        </tr>
18
+        <tr>
19
+            <td>Per entry added</td>
20
+            <td>{{ contest.bonusPerEntry|number_format(2) }}</td>
21
+        </tr>
22
+        <tr>
23
+            <td>Status of payout</td>
24
+            <td>{{ contest.bonusStatus }}</td>
25
+        </tr>
26
+    {% if contest.paymentRead %}
27
+        <tr>
28
+            <td>Payout is ready</td>
29
+            <td><input type="submit" name="payment" value="Initiate payment"/></td>
30
+        </tr>
31
+    {% endif %}
32
+    </table>
33
+</div>
34
+{% endif %}
35
+    <table>
36
+        <tr>
37
+            <td class="label">Contest name:</td>
38
+            <td>
39
+                <p>Edit the name of the contest</p>
40
+                <input type="text" size="80" name="name" value="{{ create ? '' : contest.name }}"/>
41
+            </td>
42
+        </tr>
43
+
44
+        <tr>
45
+            <td class="label">Contest type:</td>
46
+            <td>
47
+                <p>Edit the type of the contest</p>
48
+                <select name="type">
49
+{% for t in type %}
50
+                    <option value="{{ t.id }}"{{ t.name == contest.contestType ? ' selected' : '' }}>{{ t.name }}</option>
51
+{% endfor %}
52
+                </select>
53
+            </td>
54
+        </tr>
55
+
56
+        <tr>
57
+            <td class="label">Bonus Point pool:</td>
58
+            <td>
59
+                <p>Members can contribute their Bonus Points to an award pool</p>
60
+                <input type="checkbox" name="pool" value="{{ create ? 0 : contest.hasBonusPool }}"{{ contest.hasBonusPool ? ' checked' : '' }}/>
61
+            </td>
62
+        </tr>
63
+
64
+{% if create or has_pool %}
65
+        <tr>
66
+            <td class="label">Bonus Point distribution:</td>
67
+            <td>
68
+                <p>The bonus pool is divided into three parts. Adjust the values according to specifiy the proportions. Their sum
69
+                does not need to add up to anything in particular: they will be scaled to the interval [0, 1] and the sum == 1.</p>
70
+
71
+                <input type="number" min="0" max="10000" id="pool-user" name="pool-user" value="{{ create ? 5 : contest.bonusPerUserValue }}"
72
+                />&nbsp;<label for="pool-user">This proportion of the pool will be shared between all enabled users. The number of users may vary
73
+                over time; the exact value will be known only at the end of the contest.<br />
74
+
75
+                <input type="number" min="0" max="10000" id="pool-contest" name="pool-contest" value="{{ create ? 15 : contest.bonusPerContestValue }}"
76
+                />&nbsp;<label for="pool-contest">This proportion of the pool will be shared between all users who
77
+                participate in the contest (i.e. at least one entry).<br />
78
+
79
+                <input type="number" min="0" max="10000" id="pool-entry" name="pool-entry" value="{{ create ? 80 : contest.bonusPerEntryValue }}"
80
+                />&nbsp;<label for="pool-entry">This proportion of the pool will be shared between every entry in the contest.
81
+            </td>
82
+        </tr>
83
+{% endif %}
84
+
85
+        <tr>
86
+            <td class="label">Begin date:</td>
87
+            <td>
88
+                <p>Uploaded torrents/completed requests are counted from this date (yyyy/mm/dd hh:mm:ss)</p>
89
+                <input type="text" size="20" name="date_begin" value="{{ create ? '' : contest.dateBegin }}"/>
90
+            </td>
91
+        </tr>
92
+
93
+        <tr>
94
+            <td class="label">End date:</td>
95
+            <td>
96
+                <p>Uploaded torrents/completed requests are counted up until this date (yyyy/mm/dd hh:mm:ss)</p>
97
+                <input type="text" size="20" name="date_end" value="{{ create ? '' : contest.dateEnd }}"/>
98
+            </td>
99
+        </tr>
100
+
101
+        <tr>
102
+            <td class="label">Displayed:</td>
103
+            <td>
104
+                <p>This many people will be displayed on the ladderboard</p>
105
+                <input type="text" size="20" name="display" value="{{ create ? 100 : contest.display }}"/>
106
+            </td>
107
+        </tr>
108
+
109
+        <tr>
110
+            <td class="label">Banner:</td>
111
+            <td>
112
+                <p>This is the image displayed at the top of the page (optional).
113
+                   May be a local asset, or a URL.</p>
114
+                <input type="text" size="60" name="banner" value="{{ create ? '' : contest.banner }}"/>
115
+            </td>
116
+        </tr>
117
+
118
+        <tr>
119
+            <td class="label">Introduction:</td>
120
+            <td>
121
+                <p>This is the introduction / guide of the contest.</p>
122
+                {{ intro.emit|raw }}
123
+            </td>
124
+        </tr>
125
+
126
+    </table>
127
+    <input type="hidden" name="userid" value="{{ user_id }}"/>
128
+    <input type="hidden" name="auth" value="{{ auth }}"/>
129
+{% if create %}
130
+    <input type="hidden" name="new" value="1"/>
131
+    <input type="submit" id="submit" value="Create contest"/>
132
+{% else %}
133
+    <input type="hidden" name="cid" value="{{ contest.id }}"/>
134
+    <input type="submit" id="submit" value="Save contest"/>
135
+{% endif %}
136
+</form>
137
+

+ 16
- 0
templates/contest/intro.twig View File

@@ -0,0 +1,16 @@
1
+{% if contest is empty %}
2
+<div class="thin">
3
+    <div class="box pad" style="padding: 10px 10px 10px 20px;">
4
+        <p>Looks like the contest hasn't begun yet!</p>
5
+    </div>
6
+    </div>
7
+{% else %}
8
+{% if contest.banner %}
9
+<div class="pad">
10
+    <img border="0" src="{{ contest.banner }}" alt="{{ contest.name }}" width="640" height="125" style="display: block; margin-left: auto; margin-right: auto;"/>
11
+</div>
12
+{% endif %}
13
+<div class="box pad">
14
+    {{ contest.description|bb_format }}
15
+</div>
16
+{% endif %}

+ 34
- 0
templates/contest/leaderboard.twig View File

@@ -0,0 +1,34 @@
1
+<div class="head">
2
+{% if contest.hasBonusPool %}
3
+    <h3>The Bonus Point pool currently stands at {{ contest.bonusPoolTotal|number_format }} points.</h3>
4
+{% endif %}
5
+{% if not contest.isOpen and contest.totalEntries == 0 %}
6
+    <p>That's not supposed to happen. Looks like the contest hasn't begun yet!<p>
7
+{% elseif contest.totalEntries == 0 %}
8
+    <p>The scheduler has not run yet, there are no results to display.<p>
9
+{% else %}
10
+    <h3>A grand total of {{ contest.totalEntries|number_format }} {{ action_header }}.</h3>
11
+</div>
12
+{{ paginator.linkbox|raw }}
13
+{% set rank = (paginator.page - 1) * paginator.limit %}
14
+<table class="layout">
15
+    <tr>
16
+    <th style="text-align:left">Rank</th>
17
+    <th style="text-align:left">Who</th>
18
+    <th style="text-align:left">Most recent {{ action }}</th>
19
+    <th style="text-align:left">Most recent time</th>
20
+    <th style="text-align:left">{{ score_header }}</th>
21
+    </tr>
22
+    {% for entry in contest.leaderboard(paginator.limit, paginator.offset) %}
23
+        {% set rank = rank + 1 %}
24
+    <tr>
25
+        <td>{{ rank|number_format }}</td>
26
+        <td class="nowrap"><a href="/user.php?id={{ entry.user_id }}">{{ entry.username}}</a>{% if entry.user_id == viewer %} (that's you!){% endif %}</td>
27
+        <td>{{ entry.last_entry_link|raw }}</td>
28
+        <td class="nowrap">{{ entry.last_upload|time_diff }} </td>
29
+        <td>{{ entry.entry_count }}</td>
30
+    </tr>
31
+    {% endfor %}
32
+</table>
33
+{{ paginator.linkbox|raw }}
34
+{% endif %}

+ 25
- 0
templates/contest/list.twig View File

@@ -0,0 +1,25 @@
1
+{% if list is not empty %}
2
+    {% for contest in list %}
3
+        {% if loop.first %}
4
+<div class="box pad">
5
+    <table>
6
+        <tr class="colhead">
7
+            <td>Name</td>
8
+            <td>Contest Type</td>
9
+            <td>Begins</td>
10
+            <td>Ends</td>
11
+        </tr>
12
+        {% endif %}
13
+        <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
14
+            <td>{%- if current == contest.id -%}&nbsp;{{ pointer|raw }}{%- endif -%}
15
+                <a href="contest.php?action=admin&id={{ contest.id }}">{{ contest.name }}</a></td>
16
+            <td>{{ contest.contestType }}</td>
17
+            <td>{{ contest.dateBegin }}</td>
18
+            <td>{{ contest.dateEnd }}</td>
19
+        </tr>
20
+        {% if loop.last %}
21
+    </table>
22
+        {% endif %}
23
+    {% endfor %}
24
+</div>
25
+{% endif %}

+ 17
- 0
templates/contest/payout-uploader.twig View File

@@ -0,0 +1,17 @@
1
+{% set user_bonus = per_entry_bonus * total_entries %}
2
+Dear {{ username }},
3
+
4
+{% if total_entries > 0 %}
5
+During {{ name }} that ran from {{ date.begin }} to {{ date.end }}, you uploaded {{ total_entries }} {{ entries }}. Each upload turned out to be worth {{ per_entry_bonus|number_format(2) }} bonus points, so your uploading activity earnt you a total of {{ user_bonus|number_format(2) }} points!
6
+
7
+On top of that, just because you participated, you have been awarded a further {{ contest_bonus|number_format(2) }} points. And since you are awesome and are on Orpheus anyway, the cherry on top is an additional {{ enabled_bonus|number_format(2) }} points.
8
+
9
+All in all, you have been granted {{ (enabled_bonus + contest_bonus + user_bonus)|number_format(2) }} bonus points. Enjoy!
10
+{% else %}
11
+During {{ name }} that ran from {{ date.begin }} to {{ date.end }}, you didn't upload anything. So sad, because you missed out on {{ contest_bonus|number_format(2) }} bonus pointsjust for participating even once, and an additional {{ per_entry_bonus|number_format(2) }} points for each successful upload.
12
+
13
+All is not lost, because thanks to the love and generosity of the Orpheus community, you have been granted {{ enabled_bonus|number_format(2) }} bonus points for having being here during the contest!
14
+{% endif %}
15
+
16
+<3
17
+Orpheus Staff

+ 11
- 0
templates/contest/switcher.twig View File

@@ -0,0 +1,11 @@
1
+{% from 'macro/form.twig' import selected %}
2
+{% if prior %}
3
+<form class="edit_form" style="float: right;" action="contest.php?action=leaderboard" method="post">
4
+    <select name="leaderboard">
5
+    {% for p in prior %}
6
+        <option value="{{ p.id }}"{{ selected(p.id == current) }}>{{ p.name }}</option>
7
+    {% endfor %}
8
+    </select>
9
+    <input type="submit" id="view" value="view" />
10
+</form>
11
+{% endif %}

+ 24
- 0
templates/debug/cache.twig View File

@@ -0,0 +1,24 @@
1
+{% for key, value in list %}
2
+    {% if loop.first %}
3
+<table class="layout" width="100%">
4
+    <tr>
5
+        <td align="left"><strong><a href="#" id="debug-view-cache" class="brackets">View</a>
6
+        {{ list|length|number_format }} Cache key{% if list|length > 1 %}s{% endif %}
7
+        ({{ time|number_format(5) }} ms):</strong></td>
8
+    </tr>
9
+</table>
10
+<table id="debug_cache" class="debug_table hidden">
11
+    {% endif %}
12
+    <tr>
13
+        <td class="label nobr debug_info debug_cache_key">
14
+            <a href="#" onclick="$('#debug_cache_{{ key }}').gtoggle(); return false;">{{ key }}</a>
15
+            <a href="tools.php?action=clear_cache&amp;key={{ key }}&amp;type=clear" target="_blank" class="brackets tooltip" title="Flush this cache key">Flush</a>
16
+        </td>
17
+        <td align="left" class="debug_data debug_cache_data">
18
+            <pre id="debug_cache_{{ key }}" class="hidden">{{ value }}</pre>
19
+        </td>
20
+    </tr>
21
+    {% if loop.last %}
22
+</table>
23
+    {% endif %}
24
+{% endfor %}

+ 40
- 0
templates/debug/class.twig View File

@@ -0,0 +1,40 @@
1
+<table class="layout" width="100%">
2
+    <tr>
3
+        <td align="left"><strong><a href="#" id="debug-view-class" class="brackets">View</a>
4
+        Classes:</strong></td>
5
+    </tr>
6
+</table>
7
+<table id="debug_class" class="debug_table hidden">
8
+    <tr>
9
+        <th>Class</th>
10
+        <th>Methods</th>
11
+        <th>Variables</th>
12
+    </tr>
13
+{% for name, class in list %}
14
+    <tr>
15
+        <td style="vertical-align: top">{{ name }}</td>
16
+        <td style="vertical-align: top">
17
+    {% for name in class.methods %}
18
+        {% if loop.first %}
19
+            <ul class="stats nobullet">
20
+        {% endif %}
21
+                <li>{{ name }}</li>
22
+        {% if loop.last %}
23
+            </ul>
24
+        {% endif %}
25
+    {% endfor %}
26
+        </td>
27
+        <td style="vertical-align: top">
28
+    {% for name in class.vars %}
29
+        {% if loop.first %}
30
+            <ul class="stats nobullet">
31
+        {% endif %}
32
+                <li>{{ dump(name) }}</li>
33
+        {% if loop.last %}
34
+            </ul>
35
+        {% endif %}
36
+    {% endfor %}
37
+        </td>
38
+    </tr>
39
+{% endfor %}
40
+</table>

+ 25
- 0
templates/debug/error.twig View File

@@ -0,0 +1,25 @@
1
+{% for error in list %}
2
+    {% if loop.first %}
3
+<table class="layout" width="100%">
4
+    <tr>
5
+        <td align="left"><strong><a href="#" id="debug-view-error" class="brackets">View</a>
6
+        {{ list|length|number_format }} Errors:</strong></td>
7
+    </tr>
8
+</table>
9
+<table id="debug_error" class="debug_table hidden">
10
+    {% endif %}
11
+    <tr valign="top">
12
+        <td align="left" class="debug_info debug_error_call">
13
+            {{ error.2 }}({{ error.3 }})
14
+        </td>
15
+        <td class="debug_data debug_error_data" align="left">
16
+            {{ error.0 }}
17
+        </td>
18
+        <td align="left">
19
+            {{ error.1 }}
20
+        </td>
21
+    </tr>
22
+    {% if loop.last %}
23
+</table>
24
+    {% endif %}
25
+{% endfor %}

+ 16
- 0
templates/debug/extension.twig View File

@@ -0,0 +1,16 @@
1
+<table class="layout" width="100%">
2
+    <tr>
3
+        <td align="left"><strong><a href="#" id="debug-view-extension" class="brackets">View</a>
4
+        Extensions:</strong></td>
5
+    </tr>
6
+</table>
7
+<table id="debug_extension" class="debug_table hidden">
8
+{% for name, extension in list %}                
9
+    <tr>
10
+        <td style="vertical-align: top">{{ name }}</td>
11
+        <td>
12
+    {%- for e in extension %}{{ e }} {% endfor -%}
13
+        </td>
14
+    </tr>
15
+{% endfor %}
16
+</table>

+ 30
- 0
templates/debug/flag.twig View File

@@ -0,0 +1,30 @@
1
+{% for row in list %}
2
+    {% if loop.first %}
3
+<table class="layout" width="100%">
4
+    <tr>
5
+        <td align="left"><strong><a href="#" id="debug-view-flag" class="brackets">View</a>
6
+        Flags:</strong></td>
7
+    </tr>
8
+</table>
9
+<table id="debug_flag" class="debug_table hidden">
10
+    <tr valign="top">
11
+        <td class="debug_flags_event"><strong>Event</strong></td>
12
+        <td style="text-align: right" class="debug_flags_time"><strong>Page time</strong></td>
13
+        {% if row.3 is not empty %}
14
+        <td style="text-align: right" class="debug_flags_time"><strong>CPU time</strong></td>
15
+        {% endif %}
16
+        <td style="text-align: right" class="debug_flags_memory"><strong>Memory</strong></td>
17
+    </tr>
18
+    {% endif %}
19
+    <tr valign="top">
20
+        <td>{{ row.0 }}</td>
21
+        <td style="text-align: right">{{ row.1|number_format(3) }} ms</td>
22
+    {% if row.3 is not empty %}
23
+        <td style="text-align: right">{{ (row.3 / 1000)|number_format(3) }} ms</td>
24
+    {% endif %}
25
+        <td style="text-align: right">{{ row.2|octet_size }}</td>
26
+    </tr>
27
+    {% if loop.last %}
28
+</table>
29
+    {% endif %}
30
+{% endfor %}

+ 13
- 0
templates/debug/include.twig View File

@@ -0,0 +1,13 @@
1
+<table class="layout" width="100%">
2
+    <tr>
3
+        <td align="left"><strong><a href="#" id="debug-view-include" class="brackets">View</a>
4
+        {{ list|length|number_format }} Includes:</strong></td>
5
+    </tr>
6
+</table>
7
+<table id="debug_include" class="debug_table hidden">
8
+{% for file in list %}
9
+    <tr valign="top">
10
+        <td>{{ file }}</td>
11
+    </tr>
12
+{% endfor %}
13
+</table>

+ 27
- 0
templates/debug/ocelot.twig View File

@@ -0,0 +1,27 @@
1
+{% for n, request in list %}
2
+    {% if loop.first %}
3
+        {% set nr = list|length %}
4
+<table class="layout" width="100%">
5
+    <tr>
6
+        <td align="left"><strong><a href="#" id="debug-view-ocelot" class="brackets">View</a>
7
+        {{ nr|number_format }} Ocelot request{% if nr > 1 %}s{% endif %}s:</strong></td>
8
+    </tr>
9
+</table>
10
+<table id="debug_ocelot" class="debug_table hidden">
11
+    {% endif %}
12
+    <tr>
13
+        <td align="left" class="debug_data debug_ocelot_data">
14
+            <a href="#" onclick="$('#debug_ocelot_{{ n }}').gtoggle(); return false">{{ request.path }}</a>
15
+            <pre id="debug_ocelot_{{ n }}" class="hidden">{{ request.response }}</pre>
16
+        </td>
17
+        <td align="left" class="debug_info" style="width: 100px;">
18
+            {{ request.status }}
19
+        </td>
20
+        <td align="left" class="debug_info debug_timing" style="width: 100px;">
21
+            {{ request.time|number_format(5) }} ms
22
+        </td>
23
+    </tr>
24
+    {% if loop.last %}
25
+</table>
26
+    {% endif %}
27
+{% endfor %}

+ 14
- 0
templates/debug/performance.twig View File

@@ -0,0 +1,14 @@
1
+<table class="layout" width="100%">
2
+    <tr>
3
+        <td align="left"><strong><a href="#" id="debug-view-perf" class="brackets">View</a>
4
+        Performance Statistics:</strong></td>
5
+    </tr>
6
+</table>
7
+<table id="debug_perf" class="debug_table hidden">
8
+{% for stat, value in list %}
9
+    <tr valign="top">
10
+        <td class="debug_perf_stat">{{ stat }}</td>
11
+        <td class="debug_perf_data">{{ value }}</td>
12
+    </tr>
13
+{% endfor %}
14
+</table>

+ 31
- 0
templates/debug/query.twig View File

@@ -0,0 +1,31 @@
1
+{% for query in list %}
2
+    {% if loop.first %}
3
+        {% set nr = list|length %}
4
+<table class="layout" width="100%">
5
+    <tr>
6
+        <td align="left"><strong><a href="#" id="debug-view-query" class="brackets">View</a>
7
+        {{ nr|number_format }} {% if list|length == 1 %}Query{% else %}Queries{% endif %}
8
+        ({{ time|number_format(5) }} ms):</strong></td>
9
+    </tr>
10
+</table>
11
+<table id="debug_query" class="debug_table hidden">
12
+    {% endif %}
13
+    <tr valign="top">
14
+        <td class="debug_data debug_query_data">{{ query.0|raw }}</td>
15
+        <td class="rowa debug_info debug_query_time" style="width: 130px;" align="right">{{ query.1|number_format(5) }} ms</td>
16
+        <td class="rowa debug_info debug_query_warnings">
17
+        {% for warning in query.2 %}
18
+            {% if loop.first %}
19
+                <ul class="stats nobullet">
20
+            {% endif %}
21
+                    <li>{{ warning }}</li>
22
+            {% if loop.last %}
23
+                </ul>
24
+            {% endif %}
25
+         {% endfor %}
26
+        </td>
27
+    </tr>
28
+    {% if loop.list %}
29
+</table>
30
+    {% endif %}
31
+{% endfor %}

+ 20
- 0
templates/debug/sphinxql.twig View File

@@ -0,0 +1,20 @@
1
+{% for query in list %}
2
+    {% if loop.first %}
3
+        {% set nr = list|length %}
4
+<table class="layout" width="100%">
5
+    <tr>
6
+        <td align="left"><strong><a href="#" id="debug-view-sphinxql" class="brackets">View</a>
7
+        {{ nr }} Sphinx search{% if n > 1 %}s{% endif %}
8
+        ({{ time|number_format(5) }} ms):</strong></td>
9
+    </tr>
10
+</table>
11
+<table id="debug_sphinxql" class="debug_table hidden">
12
+    {% endif %}
13
+    <tr valign="top">
14
+        <td class="debug_data debug_sphinx_data"><pre>{{ query.0 }}</pre></td>
15
+        <td class="rowa debug_info debug_sphinx_time" style="width: 130px;" align="left">{{ query.1|number_format(5) }} ms</td>
16
+    </tr>
17
+    {% if loop.last %}
18
+</table>
19
+    {% endif %}
20
+{% endfor %}

+ 27
- 0
templates/debug/task.twig View File

@@ -0,0 +1,27 @@
1
+{% for id, task in list %}
2
+    {% if loop.first %}
3
+        {% set nr = list|length %}
4
+<table class="layout" width="100%">
5
+    <tr>
6
+        <td align="left"><strong><a href="#" id="debug-view-task" class="brackets">View</a>
7
+        {{ nr|number_format }} Task{% if nr > 1 %}s{% endif %}:
8
+    </tr>
9
+</table>
10
+<table id="debug_task" class="debug_table hidden">
11
+    <tr class="colhead">
12
+        <td>Task</td>
13
+        <td>Start</td>
14
+        <td>Duration</td>
15
+        <td>Processed / Errors</td>
16
+    </tr>
17
+    {% endif %}
18
+    <tr valign="top">
19
+        <td class="debug_data debug_task_data"><a href="tools.php?action=periodic&amp;mode=detail&amp;id={{ id }}">{{ task.name }}</a></td>
20
+        <td class="rowa debug_info debug_task_start">{{ task.launch_time }}</td>
21
+        <td class="rowa debug_info debug_task_time" style="width: 130px;" align="right">{{ task.duration_ms }} ms</td>
22
+        <td class="rowa debug_info debug_task_processed">{{ task.num_items|number_format }}> / {{ tasak.num_errors|number_format }}</td>
23
+    </tr>
24
+    {% if loop.last %}
25
+</table>
26
+    {% endif %}
27
+{% endfor %}

+ 24
- 0
templates/debug/var.twig View File

@@ -0,0 +1,24 @@
1
+{% for id, var in list %}
2
+    {% if loop.first %}
3
+        {% set nr = list|length %}
4
+<table class="layout" width="100%">
5
+    <tr>
6
+        <td align="left"><strong><a href="#" id="debug-view-var" class="brackets">View</a>
7
+        {{ nr }} Logged Variable{% if nr > 1 %}s{% endif %}:</strong></td>
8
+    </tr>
9
+</table>
10
+<table id="debug_var" class="debug_table hidden">
11
+    {% endif %}
12
+    <tr>
13
+        <td style="vertical-align: top" align="left" class="debug_info debug_loggedvars_name">
14
+            <a href="#" onclick="$('#debug_loggedvars_{{ id }}').gtoggle(); return false;">{{ var.name }}</a>
15
+            <div>{{ var.path }}:{{ var.line }}</div>
16
+        </td>
17
+        <td class="debug_data debug_loggedvars_data" align="left">
18
+            <pre id="debug_loggedvars_{{ id }}" class="hidden">{{ var.data }}</pre>
19
+        </td>
20
+    </tr>
21
+    {% if loop.last %}
22
+</table>
23
+    {% endif %}
24
+{% endfor %}

+ 69
- 0
templates/donation/admin-panel.twig View File

@@ -0,0 +1,69 @@
1
+<table class="layout" id="donation_box">
2
+    <tr class="colhead">
3
+        <td colspan="2">
4
+            Donations
5
+        </td>
6
+    </tr>
7
+    <tr><td></td><td><b>Manual Donation</b></td></tr>
8
+    <tr>
9
+        <td class="label">Value:</td>
10
+        <td>
11
+            <input type="text" name="donation_value" />
12
+            <select name="donation_currency">
13
+                <option value="EUR">EUR</option>
14
+                <option value="USD">USD</option>
15
+                <option value="XBT" selected="selected">XBT</option>
16
+            </select>
17
+        </td>
18
+    </tr>
19
+    <tr>
20
+        <td class="label">Reason:</td>
21
+        <td><input type="text" class="wide_input_text" name="donation_reason" /></td>
22
+    </tr>
23
+    <tr>
24
+        <td>&nbsp;</td>
25
+        <td>
26
+            <input type="submit" name="donor_points_submit" value="Add donation" />
27
+        </td>
28
+    </tr>
29
+    <tr>
30
+        <td>&nbsp;</td>
31
+        <td><b>Donation point adjustement</b></td>
32
+    </tr>
33
+    <tr>
34
+        <td colspan="2">Use this section only when manually adjusting
35
+        values. If crediting donations normally, use the Manual Donation
36
+        section. Active points represent the donation amount that has
37
+        not yet expired. Total points represent the combined amount of
38
+        all donations and never expire. These are used to determine the
39
+        Special Rank and Leaderboard placement of a member.</td>
40
+    </tr>
41
+    <tr>
42
+        <td class="label">Special Rank:</td>
43
+        <td><b> {{ user.specialDonorRank }} </b></td>
44
+    </tr>
45
+    <tr>
46
+        <td class="label">Adjust active points:</td>
47
+        <td>
48
+        <input type="text" width="4" name="donor_rank_delta" value="0" />
49
+        (add or subtract) currently: <b>{{ user.donorRank }}</b>
50
+        </td>
51
+    </tr>
52
+    <tr>
53
+        <td class="label">Adjust total points:</td>
54
+        <td>
55
+        <input type="text" width="4" name="total_donor_rank_delta" value="0" />
56
+        (add or subtract) currently: <b>{{ user.totalDonorRank }}</b>
57
+        </td>
58
+    </tr>
59
+    <tr>
60
+        <td class="label">Reason:</td>
61
+        <td><input type="text" class="wide_input_text" name="reason" /></td>
62
+    </tr>
63
+    <tr>
64
+        <td>&nbsp;</td>
65
+        <td align="right" colspan="2">
66
+            <input type="submit" name="donor_values_submit" value="Change point values" />
67
+        </td>
68
+    </tr>
69
+</table>

+ 13
- 0
templates/donation/donation-pm.twig View File

@@ -0,0 +1,13 @@
1
+Thank you for your generosity and support. It's users like you who make all of this possible. What follows is a brief description of your transaction:
2
+
3
+[*] [b]You Contributed:[/b] {{ amount }} {{ cc }}
4
+[*] [b]You Received:[/b] {{ points }} Donor Point{{ s }}
5
+[*] [b]Your Donor Rank:[/b] Donor Rank # {{ rank }}
6
+
7
+Once again, thank you for your continued support of the site.
8
+
9
+Sincerely,
10
+{{ constant('SITE_NAME') }} Staff
11
+
12
+[align=center][[n]If you have any questions or concerns, please [url={{ staffpm_url }}]send a Staff PM[/url].
13
+

+ 55
- 0
templates/donation/history.twig View File

@@ -0,0 +1,55 @@
1
+{% for dono in history %}
2
+{% if loop.first %}
3
+<div class="box box2" id="donation_history_box">
4
+    <div class="head">
5
+        Donation History <a href="#" onclick="$('#donation_history').gtoggle(); return false;" class="brackets">View</a>
6
+    </div>
7
+    <div class="hidden" id="donation_history">
8
+        <table cellpadding="6" cellspacing="1" border="0" class="border" width="100%">
9
+            <tbody>
10
+            <tr class="colhead_dark">
11
+                <td><strong>Source</strong></td>
12
+                <td>
13
+                    <strong>Date</strong>
14
+                </td>
15
+                <td>
16
+                    <strong>Amount (EUR)</strong>
17
+                </td>
18
+                <td>
19
+                    <strong>Added Points</strong>
20
+                </td>
21
+                <td>
22
+                    <strong>Total Points</strong>
23
+                </td>
24
+                <td style="width: 30%;">
25
+                    <strong>Reason</strong>
26
+                </td>
27
+            </tr>
28
+{% endif %}
29
+            <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
30
+                <td>
31
+                    {{ dono.Source }} ({{ dono.AddedBy|user_url }})
32
+                </td>
33
+                <td>
34
+                    {{ dono.Time }}
35
+                </td>
36
+                <td>
37
+                    {{ dono.Amount }}
38
+                </td>
39
+                <td>
40
+                    {{ dono.Rank }}
41
+                </td>
42
+                <td>
43
+                    {{ dono.TotalRank }}
44
+                </td>
45
+                <td>
46
+                    {{ dono.Reason }}
47
+                </td>
48
+            </tr>
49
+{% if loop.last %}
50
+            </tbody>
51
+        </table>
52
+    </div>
53
+</div>
54
+{% endif %}
55
+{% endfor %}

+ 57
- 0
templates/donation/reward-list.twig View File

@@ -0,0 +1,57 @@
1
+<div class="header">
2
+    <h2>{{ title }}</h2>
3
+    <div class="linkbox">
4
+        {{ pages|raw }}
5
+    </div>
6
+</div>
7
+<form action="" method="get">
8
+    <input type="hidden" name="action" value="donor_rewards" />
9
+    <strong>Username (regexps allowed): </strong>
10
+    <input type="search" name="username" />
11
+</form>
12
+<br />
13
+
14
+{% for u in user %}
15
+    {% if loop.first %}
16
+<table style="table-layout: fixed; width: 100%;">
17
+    <tr class="colhead">
18
+        <td>Username</td>
19
+        <td>Rank</td>
20
+        <td>Hidden</td>
21
+        <td>Last Donated</td>
22
+        <td>Icon Text</td>
23
+        <td>Icon</td>
24
+        <td>Icon Link</td>
25
+        <td>Avatar Text</td>
26
+        <td>Second Avatar</td>
27
+    </tr>
28
+    {% endif %}
29
+    <tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
30
+        <td>{{ u.user_id|user_full }}</td>
31
+        <td>{{ u.rank }}</td>
32
+        <td>{{ u.hidden }}</td>
33
+        <td>{{ u.donation_time|time_diff }}</td>
34
+        <td style="word-wrap: break-word;">
35
+           {{ u.icon_mouse }}
36
+        </td>
37
+        <td style="word-wrap: break-word;">
38
+    {% if u.custom_icon %}
39
+            <img src="{{ donor_icon(u.custom_icon, u.user_id) }}" width="15" height="13" alt="" />
40
+    {% endif %}
41
+        </td>
42
+        <td style="word-wrap: break-word;">
43
+            {{ u.custom_icon }}
44
+        </td>
45
+        <td style="word-wrap: break-word;">
46
+            {{ u.avatar_mouse }}
47
+        </td>
48
+        <td style="word-wrap: break-word;">
49
+            {{ u.second_avatar }}
50
+        </td>
51
+    </tr>
52
+    {% if loop.last %}
53
+</table>
54
+    {% endif %}
55
+{% endfor %}
56
+
57
+<div class="linkbox">{{ pages|raw }}</div>

+ 111
- 0
templates/donation/special-rank-1.twig View File

@@ -0,0 +1,111 @@
1
+Congratulations on reaching [url={{ forum_url }}]Special Rank #1[/url]! You've been awarded [b]one user pick[/b]! This user pick will be featured on the {{ constant('SITE_NAME') }} front page during an upcoming event. After you submit your pick, there is no guarantee as to how long it will take before your pick is featured. Picks will be featured on a first-submitted, first-served basis. Please abide by the following guidelines when making your selection:
2
+
3
+[*] Pick something that hasn't been chosen. You can tell if a pick has been used previously by reviewing the collages it appears in.
4
+[*] If the only release is a CD rip, please ensure it is not trumpable for bad or missing checksums.
5
+[*] Complete the enclosed form carefully and completely.
6
+[*] Send a [url={{ staffpm_url }}]Staff PM[/url], entitle this PM "Special Rank User Pick", and choose "Staff" as recipient.
7
+
8
+[important][align=center]**The following form must be used. Do not edit the
9
+BBCode. Reply to this message with the completed form.**[/align][/important]
10
+
11
+[quote][align=center][size=10]SUBMISSION FORM[/size]
12
+[size=4]COPY & PASTE THE BBCODE INTO YOUR REPLY. FILL FORM WITH YOUR INFO. SUBMIT.[/size][/align]
13
+
14
+[code][align=center][size=10][u]FRONT PAGE[/u][/size][/align]
15
+
16
+[b][size=5][user]<NAME>[/user]'s Special Donor Pick[/size][/b]
17
+
18
+[b]Artist Name - Album Title[/b]
19
+
20
+[b]Genre:[/b] Alternative, Rock, Grunge, ...
21
+
22
+[b]Torrents:[/b] Torrent Group Link Here
23
+
24
+[b]Review:[/b] [quote]Put your front page review here. The review should be a maximum of two small(ish) paragraphs or one medium-sized paragraph. Do not include a huge review for the front page portion of your post, as it will be truncated per the wishes of the Staff Team.[/quote]
25
+
26
+[align=center][size=10][u]FORUM POST[/u][/size][/align]
27
+
28
+[b][size=5][user]<NAME>[/user]'s Special Donor Pick[/size][/b]
29
+
30
+[img]Album Cover URL[/img]
31
+
32
+[b]Artist Name - Album Title[/b]
33
+
34
+[b]Genre:[/b] Alternative, Rock, Grunge, ...
35
+
36
+[b]Torrents:[/b] Torrent Group Link Here
37
+
38
+[b]Release Info:[/b]
39
+[*][u]Release Date[/u]: Release Date Here
40
+[*][u]Tracks[/u]: Track Count Here
41
+[*][u]Length[/u]: Release Length Here
42
+[*][u]Label[/u]: Release Label Here
43
+
44
+[b]Credits:[/b]
45
+[*][b]Member Name 1:[/b] Role / Instruments Played
46
+[*][b]Member Name 2:[/b] Role / Instruments Played
47
+[*][b]Member Name 3:[/b] Role / Instruments Played
48
+
49
+[b]Track Listing:[/b]
50
+[#]Remove or add to this list...
51
+[#]...as is necessary.
52
+[#]Track 03
53
+[#]Track 04
54
+[#]Track 05
55
+[#]Track 06
56
+
57
+[b]Web site:[/b] Artist Web Site / Discogs Page / Bandcamp Page / Fan Site Link Here
58
+
59
+[b]Review:[/b] [quote]Put your forum post review here. This review can be any length, but please be reasonable. You can write it yourself or source it from the Internet. Please try to include a source if you don't write your own review. If your review is too long, it will be included but put into "hide" tags by the person formatting the thread.[/quote][/code][/quote]
60
+
61
+[hide=Completed Submission Form (Example)][align=center][size=10][u]FRONT PAGE[/u][/size][/align]
62
+
63
+[b][size=5][user]Not_Spine[/user]'s Special Donor Pick[/size][/b]
64
+
65
+[b]The Door and The Window - Detailed Twang[/b]
66
+
67
+[b]Genre:[/b] Post-Punk, Rock, Experimental
68
+
69
+[b]Torrents:[/b] https://orpheus.network/torrents.php?id=1
70
+
71
+[b]Review:[/b] [quote=Mutant Sounds]Stumblebum idiot savant songform fragmentation that vacillates between moments of delirious jerry-rigged inspiration and passages that border on the insufferably sophomoric, brought to you by this batch of DIY rabble rousers whose stance and attitude (complete with DIY manifestos on the back cover) aligned them strongly at the time with the likes of The Desperate Bicycles. Loosely yoked to a whole network of willfully rinky dink art damage, Nag and Bendle (2/3 of The Door And The Window) also participated in The 49 Americans, a group with a similar propensity for inspired faux naif art brut whimsy and Mark Perry (the other 1/3) was of course the leader of Alternative TV, whose NWW list included group The Good Missionaries also traffic in much the same sort of abstruse fuckery.[/quote]
72
+
73
+
74
+[align=center][size=10][u]FORUM POST[/u][/size][/align]
75
+
76
+[b][size=5][user]Not_Spine[/user]'s Special Donor Pick[/size][/b]
77
+
78
+[img]https://i.imgur.com/wXdQd.jpg[/img]
79
+
80
+[b]The Door and The Window - Detailed Twang[/b]
81
+
82
+[b]Genre:[/b] Post-Punk, Rock, Experimental
83
+
84
+[b]Torrents:[/b] https://orpheus.network/torrents.php?id=1
85
+
86
+[b]Release Info:[/b]
87
+[*][u]Release Date[/u]: 1980 (Reissue: 2003)
88
+[*][u]Tracks[/u]: 12 (Reissue: 23)
89
+[*][u]Length[/u]: 1:09:11
90
+[*][u]Label[/u]: Overground Records
91
+
92
+[b]Credits:[/b]
93
+[*][b]Bendle:[/b] Guitar, Percussion, Vocals
94
+[*][b]Nag:[/b] Percussion, Synthesizer, Vocals
95
+[*][b]Mark Perry:[/b] Drums, Saxophone, Vocals (tracks: 1 to 12, 22, 23)
96
+
97
+[b]Track Listing:[/b]
98
+[#]Dads (4:41)
99
+[#]Habits (2:14)
100
+[#]We Do Scare Each Other (2:23)
101
+[#]Order And Obey (3:20)
102
+[#]He Feels Like A Doris (4:47)
103
+[#]Part-Time Punks (3:50)
104
+[#]In The Car (0:43)
105
+
106
+[b]Web site:[/b] https://www.wikipedia.org
107
+
108
+[b]Review:[/b] [quote=Mutant Sounds]Stumblebum idiot savant songform fragmentation that vacillates between moments of delirious jerry-rigged inspiration and passages that border on the insufferably sophomoric, brought to you by this batch of DIY rabble rousers whose stance and attitude (complete with DIY manifestos on the back cover) aligned them strongly at the time with the likes of The Desperate Bicycles. Loosely yoked to a whole network of willfully rinky dink art damage, Nag and Bendle (2/3 of The Door And The Window) also participated in The 49 Americans, a group with a similar propensity for inspired faux naif art brut whimsy and Mark Perry (the other 1/3) was of course the leader of Alternative TV, whose NWW list included group The Good Missionaries also traffic in much the same sort of abstruse fuckery.[/quote][/hide]
109
+
110
+With :heart:,
111
+{{ constant('SITE_NAME') }} Staff

+ 8
- 0
templates/donation/special-rank-2.twig View File

@@ -0,0 +1,8 @@
1
+Congratulations on reaching [url={{ forum_url }}]Special Rank #2[/url]!
2
+
3
+You've been awarded [b]double avatar functionality[/b]! To set a second avatar, please enter a URL leading to a valid image in the new field which has been unlocked in your [b]Personal Settings[/b]. Any avatar you choose must abide by normal avatar rules. When running your cursor over your avatar, it will flip to the alternate choice you've established. Other users will also be able to view both of your avatars using this method.
4
+
5
+At this time, we'd like to thank you for your continued support of the site. The fact that you've reached this milestone is testament to your belief in {{ constant('SITE_NAME') }} as a project. It is dedicated users like you that keep us alive. Have fun with the new toy.
6
+
7
+With :heart:,
8
+{{ constant('SITE_NAME') }} Staff

+ 6
- 0
templates/donation/special-rank-3.twig View File

@@ -0,0 +1,6 @@
1
+Congratulations on reaching [url={{ forum_url }}]Special Rank #3[/url]! You've been awarded [b]Diamond Rank[/b]! Diamond Rank grants you the benefits associated with every Donor Rank up to and including Gold ([url={{ forum_gold_url }}]Donor Rank #5[/url]). But unlike Donor Rank #5 — because Diamond Rank is a Special Rank — it will never expire.
2
+
3
+At this time, we'd like to thank you for your continued support of the site. The fact that you've reached this milestone is testament to your belief in {{ constant('SITE_NAME') }} as a project. It's dedicated users like you that keep us alive. Consider yourself one of our top supporters!
4
+
5
+With all our :heart:,
6
+{{ constant('SITE_NAME') }} Staff

+ 20
- 0
templates/donation/stats.twig View File

@@ -0,0 +1,20 @@
1
+<div class="box box_info box_userinfo_donor_stats">
2
+    <div class="head colhead_dark">Donor Statistics</div>
3
+    <ul class="stats nobullet">
4
+{% if not is_donor %}
5
+{%      if is_self %}
6
+        <li>You haven't donated.</li>
7
+{%      else %}
8
+        <li>This user hasn't donated.</li>
9
+{%      endif %}
10
+{% else %}
11
+{%      if is_mod or is_self %}
12
+        <li>Total donor points: {{ total_rank }}</li>
13
+{%      endif %}
14
+        <li>Current donor rank: {{ current|raw }}</li>
15
+        <li>Leaderboard position: {{ leaderboard }}</li>
16
+        <li>Last donated: {{ last|time_diff }}
17
+        <li>Rank expires: {{ expiry|raw }}
18
+{% endif %}
19
+    </ul>
20
+</div>

+ 12
- 0
templates/email/disable-warning.twig View File

@@ -0,0 +1,12 @@
1
+Hi {{ username }},
2
+
3
+It has been almost 4 months since we last saw you at {{
4
+constant('SITE_NAME') }}. We miss you!
5
+
6
+While seeding activity is most appreciated, that is not enough to ensure
7
+that your account remains active.  Why don't you stop by and check out
8
+the forums or the Top 10?
9
+
10
+If you do not sign in within 10 day, your account will be disabled.
11
+
12
+It is as easy as clicking on this link: {{ constant('SITE_URL') }}

+ 8
- 0
templates/email/enable_request_accepted.twig View File

@@ -0,0 +1,8 @@
1
+Your request to re-enable your account has been accepted. Please use the
2
+following link to activate your account. This link is valid for 48 hours,
3
+and can be clicked only once.
4
+
5
+{{ constant('SITE_URL') }}/enable.php?token={{ token }}
6
+
7
+Thank you,
8
+{{ constant('SITE_NAME') }} Staff

+ 9
- 0
templates/email/enable_request_denied.twig View File

@@ -0,0 +1,9 @@
1
+Your request to re-enable your account was not accepted, for one or more of
2
+the following reasons:
3
+
4
+* We may require more information to verify your account ownership.
5
+* The e-mail address you provided does not match our records.
6
+* Your account may not qualify for automatic re-enabling due to rule violations.
7
+
8
+Thank you,
9
+{{ constant('SITE_NAME') }} Staff

+ 14
- 0
templates/email/hacked.twig View File

@@ -0,0 +1,14 @@
1
+Your {{ constant('SITE_NAME') }} account appears to have been compromised.
2
+As a security measure, we have disabled your account. To resolve this,
3
+please visit us on IRC.
4
+
5
+This is the information to connect to our server:
6
+IRC Server: {{ constant('BOT_SERVER') }}
7
+Port: {{ constant('BOT_PORT') }} (or {{ constant('BOT_PORT_SSL') }} for SSL).
8
+
9
+Once you are connected to the server you will need to join the disabled users channel.
10
+Type: /join {{ constant('BOT_DISABLED_CHAN') }}
11
+
12
+Please visit us soon so we can help you resolve this matter.
13
+
14
+{{ constant('SITE_NAME') }} Staff

+ 23
- 0
templates/email/invite-interviewer.twig View File

@@ -0,0 +1,23 @@
1
+The user {{ inviter_name }} has invited you to join {{ constant('SITE_NAME')
2
+}}, and has specified this address ({{ email }}) as your email address. If
3
+you do not know this person, please ignore this email, and do not reply.
4
+
5
+Please note that selling invites, trading invites, and giving invites away
6
+publicly (e.g. on a forum) is strictly forbidden. If you have received your
7
+invite as a result of any of these things, do not bother signing up - you
8
+will be banned and lose your chances of ever signing up legitimately.
9
+
10
+If you had previously had an account at {{ constant('SITE_NAME') }}, do not
11
+use this invite. Instead, please join {{ constant('DISABLED_CHAN') }} on {{
12
+constant('BOT_SERVER') }} and ask for your account to be reactivated.
13
+
14
+To confirm your invite, click on the following link:
15
+
16
+{{ constant('SITE_URL') }}/register.php?invite={{ invite_key }}
17
+
18
+After you register, you will be able to use your account. Please take note
19
+that if you do not use this invite in the next 3 days, it will expire. We
20
+urge you to read the RULES and the wiki immediately after you join.
21
+
22
+Thank you,
23
+{{ constant('SITE_NAME') }} Staff

+ 29
- 0
templates/email/invite-member.twig View File

@@ -0,0 +1,29 @@
1
+Hello,
2
+
3
+The member {{ username }} has invited you to join {{ constant('SITE_NAME') }}
4
+and has specified this address {{ email }} as your email address. If you do
5
+not know this person, please ignore this email and do not reply.
6
+
7
+Please note that selling invites, trading invites, and giving invites away
8
+publicly (e.g. on a forum) is strictly forbidden. If you have received your
9
+invite as a result of any of these things, do not bother signing up - you
10
+will be banned and lose your chances of ever signing up legitimately.
11
+
12
+If you have previously held an account at {{ constant('SITE_NAME') }}, do not use this invite.
13
+Instead, please join {{ constant('BOT_DISABLED_CHAN') }}  on {{ constant('BOT_SERVER') }}  and ask for your account
14
+to be reactivated.
15
+
16
+To confirm your invitation, click on the following link or paste it into a
17
+browser:
18
+
19
+{{ constant('SITE_URL') }}/register.php?invite={{ key }}
20
+
21
+During registration, you may use another email address if you prefer.
22
+Ideally it should not be an address used anywhere else. After you
23
+register, you will receive a confirmation email and once you have replied
24
+to that you will be able to use your account. Please take note that if you
25
+do not use this invite in the next 3 days, it will expire. We urge you to
26
+read the RULES and the wiki immediately after you join.
27
+
28
+Thank you,
29
+{{ constant('SITE_NAME') }} Staff

+ 11
- 0
templates/email/password_reset.twig View File

@@ -0,0 +1,11 @@
1
+A password reset process has been started for the username: {{ username }}
2
+
3
+To finish this process please click the link below (you have 1 hour)
4
+
5
+{{ constant('SITE_URL') }}/login.php?action=recover&key={{ reset_key }}
6
+
7
+If you did not initiate this password reset then please disregard this email.
8
+The user who requested the password reset had the IP address {{ ipaddr }}.
9
+
10
+Thank you,
11
+{{ constant('SITE_NAME') }} Staff

+ 31
- 0
templates/email/recovery.twig View File

@@ -0,0 +1,31 @@
1
+You recently requested to recover your account from a previous tracker in
2
+order to join {{ constant('SITE_NAME') }}.
3
+
4
+The information you provided was sufficient proof for confirm that you did
5
+have in fact have an account, and consequently you have been given an
6
+invitation.
7
+
8
+Please note that selling invites, trading invites, and giving invites away
9
+publicly (e.g. on a forum) is strictly forbidden. If you do any of these
10
+things with this invitation, do not bother signing up - you will be banned,
11
+the person who used the invite will be banned and you and they lose your
12
+chances of ever signing up in the future.
13
+
14
+To confirm your invite, click on the following link:
15
+
16
+{{ constant('SITE_URL') }}/register.php?invite={{ invite_key }}
17
+
18
+After you register, you will be able to use your account. Please take note
19
+that if you do not use this invite in the next 3 days, it will expire. We
20
+urge you to read the RULES and the wiki immediately after you join.
21
+
22
+MOST IMPORTANT OF ALL:
23
+
24
+You should read the following article: {{ constant('SITE_URL') }}/wiki.php?action=article&id=114
25
+
26
+This will help you understand what you need to do to begin reseeding your
27
+old torrents (and avoid downloading them all over again by accident, thereby
28
+destroying your buffer).
29
+
30
+Thank you,
31
+{{ constant('SITE_NAME') }} Staff

+ 22
- 0
templates/email/referral.twig View File

@@ -0,0 +1,22 @@
1
+Hello
2
+
3
+You have been invited to join {{ constant('SITE_NAME') }} and have specified
4
+this address ({{ email }}) as your email address.
5
+
6
+Please note that selling invites, trading invites, and giving invites away
7
+publicly (e.g. on a forum) is strictly forbidden.
8
+
9
+If you had previously had an account at {{ constant('SITE_NAME') }}, do not use this
10
+invite. Instead, please join {{ constant('DISABLED_CHAN') }} on {{ constant('BOT_SERVER') }} and ask for
11
+your account to be reactivated.
12
+
13
+To confirm your invite, click on the following link:
14
+
15
+{{ constant('SITE_URL') }}/register.php?invite={{ invite_key }}
16
+
17
+After you register, you will be able to use your account. Please take note
18
+that if you do not use this invite in the next 3 days, it will expire. We
19
+urge you to read the RULES and the wiki immediately after you join.
20
+
21
+Thank you,
22
+{{ constant('SITE_NAME') }} Staff

+ 9
- 0
templates/email/registration.twig View File

@@ -0,0 +1,9 @@
1
+This email is to confirm that you have just created an account at {{ constant('SITE_NAME') }}.
2
+
3
+You have 24 hours to click the link below and finish the registration
4
+process for the account created with the username: {{ username }}
5
+
6
+{{ constant('SITE_URL') }}/register.php?confirm={{ announce_key }}
7
+
8
+Thank you,
9
+{{ constant('SITE_NAME') }} Staff

+ 4
- 4
templates/enable_request_accepted.tpl View File

@@ -1,7 +1,6 @@
1
-Your request to re-enable your account was accepted.
1
+Your request to re-enable your account has been accepted. Please use the following link to activate your account. This link is valid for 48 hours, and can be clicked only once.
2 2
 
3
-Please click the link below to activate your account (you have 48 hours).
3
+https://{{SITE_URL}}/enable.php?token={{TOKEN}}
4 4
 
5
-https://{{SITE_DOMAIN}}/enable.php?token={{TOKEN}}
6
-
5
+Thank you,
6
+{{SITE_NAME}} Staff

+ 6
- 4
templates/enable_request_denied.tpl View File

@@ -1,7 +1,8 @@
1
-Your request to re-enable your account was denied for one or more of the reasons below.
1
+Your request to re-enable your account was not accepted, for one or more of the following reasons:
2 2
 
3
-* We require more information to verify your account ownership
4
-* The email address you provided doesn't match our records
5
-* Your account doesn't qualify for automatic re-enabling due to rule violations
3
+* We may require more information to verify your account ownership.
4
+* The e-mail address you provided does not match our records.
5
+* Your account may not qualify for automatic re-enabling due to rule violations.
6 6
 
7
+Thank you,
8
+{{SITE_NAME}} Staff

+ 46
- 46
templates/error.tpl View File

@@ -1,48 +1,48 @@
1 1
 <table cellpadding="0" cellspacing="0" border="0" style="color: black; font-family: Arial; font-size: 12px; font-weight: normal;">
2
-  <tr valign="top">
3
-    <td colspan="2" align="left" style="font-size: 14px; border-bottom: 1px solid black;"><strong>There is a new {{ErrorType}}, here are the details</strong></td>
4
-  </tr>
5
-  <tr valign="top">
6
-    <td colspan="2" height="10"></td>
7
-  </tr>
8
-  <tr valign="top">
9
-    <td align="right" style="padding: 0px 10px 0px 6px;"><strong>Description</strong></td>
10
-    <td align="left">{{Description}}</td>
11
-  </tr>
12
-  <tr valign="top">
13
-    <td colspan="2" height="5"></td>
14
-  </tr>
15
-  <tr valign="top">
16
-    <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>URL</strong></td>
17
-    <td align="left">{{URL}}</td>
18
-  </tr>
19
-  <tr valign="top">
20
-    <td colspan="2" height="5"></td>
21
-  </tr>
22
-  <tr valign="top">
23
-    <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>IP</strong></td>
24
-    <td align="left">{{IP}}</td>
25
-  </tr>
26
-  <tr valign="top">
27
-    <td colspan="2" height="5" style="border-bottom: 1px solid black;"></td>
28
-  </tr>
29
-  <tr valign="top">
30
-    <td colspan="2" height="5"></td>
31
-  </tr>
32
-  <tr valign="top">
33
-    <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Request Vars</strong></td>
34
-    <td align="left"><pre>{{RequestVars}}</pre></td>
35
-  </tr>
36
-  <tr valign="top">
37
-    <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Session Vars</strong></td>
38
-    <td align="left"><pre>{{SessionVars}}</pre></td>
39
-  </tr>
40
-  <tr valign="top">
41
-    <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Cookie Vars</strong></td>
42
-    <td align="left"><pre>{{CookieVars}}</pre></td>
43
-  </tr>
44
-  <tr valign="top">
45
-    <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Server Vars</strong></td>
46
-    <td align="left"><pre>{{ServerVars}}</pre></td>
47
-  </tr>
2
+	<tr valign="top">
3
+		<td colspan="2" align="left" style="font-size: 14px; border-bottom: 1px solid black;"><strong>There is a new {{ErrorType}}, here are the details</strong></td>
4
+	</tr>
5
+	<tr valign="top">
6
+		<td colspan="2" height="10"></td>
7
+	</tr>
8
+	<tr valign="top">
9
+		<td align="right" style="padding: 0px 10px 0px 6px;"><strong>Description</strong></td>
10
+		<td align="left">{{Description}}</td>
11
+	</tr>
12
+	<tr valign="top">
13
+		<td colspan="2" height="5"></td>
14
+	</tr>
15
+	<tr valign="top">
16
+		<td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>URL</strong></td>
17
+		<td align="left">{{URL}}</td>
18
+	</tr>
19
+	<tr valign="top">
20
+		<td colspan="2" height="5"></td>
21
+	</tr>
22
+	<tr valign="top">
23
+		<td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>IP</strong></td>
24
+		<td align="left">{{IP}}</td>
25
+	</tr>
26
+	<tr valign="top">
27
+		<td colspan="2" height="5" style="border-bottom: 1px solid black;"></td>
28
+	</tr>
29
+	<tr valign="top">
30
+		<td colspan="2" height="5"></td>
31
+	</tr>
32
+	<tr valign="top">
33
+		<td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Request Vars</strong></td>
34
+		<td align="left"><pre>{{RequestVars}}</pre></td>
35
+	</tr>
36
+	<tr valign="top">
37
+		<td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Session Vars</strong></td>
38
+		<td align="left"><pre>{{SessionVars}}</pre></td>
39
+	</tr>
40
+	<tr valign="top">
41
+		<td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Cookie Vars</strong></td>
42
+		<td align="left"><pre>{{CookieVars}}</pre></td>
43
+	</tr>
44
+	<tr valign="top">
45
+		<td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Server Vars</strong></td>
46
+		<td align="left"><pre>{{ServerVars}}</pre></td>
47
+	</tr>
48 48
 </table>

+ 48
- 0
templates/error.twig View File

@@ -0,0 +1,48 @@
1
+<table cellpadding="0" cellspacing="0" border="0" style="color: black; font-family: Arial; font-size: 12px; font-weight: normal;">
2
+    <tr valign="top">
3
+        <td colspan="2" align="left" style="font-size: 14px; border-bottom: 1px solid black;"><strong>There is a new {{ErrorType}}, here are the details</strong></td>
4
+    </tr>
5
+    <tr valign="top">
6
+        <td colspan="2" height="10"></td>
7
+    </tr>
8
+    <tr valign="top">
9
+        <td align="right" style="padding: 0px 10px 0px 6px;"><strong>Description</strong></td>
10
+        <td align="left">{{Description}}</td>
11
+    </tr>
12
+    <tr valign="top">
13
+        <td colspan="2" height="5"></td>
14
+    </tr>
15
+    <tr valign="top">
16
+        <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>URL</strong></td>
17
+        <td align="left">{{URL}}</td>
18
+    </tr>
19
+    <tr valign="top">
20
+        <td colspan="2" height="5"></td>
21
+    </tr>
22
+    <tr valign="top">
23
+        <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>IP</strong></td>
24
+        <td align="left">{{IP}}</td>
25
+    </tr>
26
+    <tr valign="top">
27
+        <td colspan="2" height="5" style="border-bottom: 1px solid black;"></td>
28
+    </tr>
29
+    <tr valign="top">
30
+        <td colspan="2" height="5"></td>
31
+    </tr>
32
+    <tr valign="top">
33
+        <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Request Vars</strong></td>
34
+        <td align="left"><pre>{{RequestVars}}</pre></td>
35
+    </tr>
36
+    <tr valign="top">
37
+        <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Session Vars</strong></td>
38
+        <td align="left"><pre>{{SessionVars}}</pre></td>
39
+    </tr>
40
+    <tr valign="top">
41
+        <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Cookie Vars</strong></td>
42
+        <td align="left"><pre>{{CookieVars}}</pre></td>
43
+    </tr>
44
+    <tr valign="top">
45
+        <td align="right" style="padding: 0px 10px 0px 6px; white-space: nowrap;"><strong>Server Vars</strong></td>
46
+        <td align="left"><pre>{{ServerVars}}</pre></td>
47
+    </tr>
48
+</table>

+ 69
- 0
templates/forum/header-thread.twig View File

@@ -0,0 +1,69 @@
1
+<div class="thin">
2
+    <h2>
3
+        <a href="forums.php">Forums</a> &rsaquo;
4
+        <a href="forums.php?action=viewforum&amp;forumid={{ forum.id }}">{{ forum.name }}</a> &rsaquo; {{ thread_title }}
5
+    </h2>
6
+    <div class="linkbox">
7
+{% for d in dept_list %}
8
+        <a class="brackets" href="forums.php?action=viewforum&amp;forumid={{ d.forum_id }}">
9
+    {%- if d.active %}<b>{% endif %}{{ d.name }}{% if d.active %}</b>{% endif -%}
10
+    {%- if d.unread %} <span title="unread">({{ d.unread|number_format }})</span>{% endif -%}
11
+        </a>
12
+{% endfor %}
13
+    </div>
14
+    <div class="linkbox">
15
+        <div class="center">
16
+            <a href="reports.php?action=report&amp;type=thread&amp;id={{ thread_id }}" class="brackets">Report thread</a>
17
+            <a href="#" onclick="Subscribe({{ thread_id }});return false;" id="subscribelink{{ thread_id }}" class="brackets">
18
+            {%- if is_subbed %}Unsubscribe{% else %}Subscribe{% endif -%}
19
+            </a>
20
+            <a href="#" onclick="$('#searchthread').gtoggle(); this.innerHTML = (this.innerHTML == 'Search this thread' ? 'Hide search' : 'Search this thread'); return false;" class="brackets">Search this thread</a>
21
+        </div>
22
+        <div id="searchthread" class="hidden center">
23
+            <div style="display: inline-block;">
24
+                <h3>Search this thread:</h3>
25
+                <form class="search_form" name="forum_thread" action="forums.php" method="get">
26
+                    <input type="hidden" name="action" value="search" />
27
+                    <input type="hidden" name="threadid" value="{{ thread_id }}" />
28
+                    <table cellpadding="6" cellspacing="1" border="0" class="layout border">
29
+                        <tr>
30
+                            <td><strong>Search for:</strong></td>
31
+                            <td><input type="search" id="searchbox" name="search" size="70" /></td>
32
+                        </tr>
33
+                        <tr>
34
+                            <td><strong>Posted by:</strong></td>
35
+                            <td><input type="search" id="username" name="user" placeholder="Username" size="70" /></td>
36
+                        </tr>
37
+                        <tr>
38
+                            <td colspan="2" style="text-align: center;">
39
+                                <input type="submit" name="submit" value="Search" />
40
+                            </td>
41
+                        </tr>
42
+                    </table>
43
+                </form>
44
+                <br />
45
+            </div>
46
+        </div>
47
+    </div>
48
+{{ paginator.linkbox|raw }}
49
+{% for t in transition %}
50
+    {% if loop.first %}
51
+    <table class="layout border">
52
+        <tr>
53
+            <td class="label">Move thread</td>
54
+            <td>
55
+    {% endif %}
56
+                <form action="forums.php" method="post" style="display: inline-block">
57
+                    <input type="hidden" name="action" value="mod_thread" />
58
+                    <input type="hidden" name="auth" value="{{ auth }}" />
59
+                    <input type="hidden" name="threadid" value="{{ thread_id }}" />
60
+                    <input type="hidden" name="page" value="{{ paginator.page }}" />
61
+                    <input type="hidden" name="transition" value="{{ t.id }}" />
62
+                    <input type="submit" value="{{ t.label }}" />
63
+                </form>
64
+    {% if loop.last %}
65
+            </td>
66
+        </tr>
67
+    </table>
68
+    {% endif %}
69
+{% endfor %}

+ 53
- 0
templates/forum/header.twig View File

@@ -0,0 +1,53 @@
1
+    <h2><a href="forums.php">Forums</a> &rsaquo; <a href="forums.php#{{ forum.categoryId }}">{{ forum.categoryName }}</a> &rsaquo; {{ forum.name }}</h2>
2
+    <div class="linkbox">
3
+{% for d in dept_list %}
4
+        <a class="brackets" href="forums.php?action=viewforum&amp;forumid={{ d.forum_id }}">
5
+    {%- if d.active %}<b>{% endif %}{{ d.name }}{% if d.active %}</b>{% endif -%}
6
+    {%- if d.unread %} <span title="unread">({{ d.unread|number_format }})</span>{% endif -%}
7
+        </a>
8
+{% endfor %}
9
+    </div>
10
+    <div class="linkbox">
11
+{% if create %}
12
+        <a href="forums.php?action=new&amp;forumid={{ forum.id }}" class="brackets">New thread</a>
13
+{% endif %}
14
+        <a href="#" onclick="$('#searchforum').gtoggle(); this.innerHTML = (this.innerHTML == 'Search this forum' ? 'Hide search' : 'Search this forum'); return false;" class="brackets">Search this forum</a>
15
+        <div id="searchforum" class="hidden center">
16
+            <div style="display: inline-block;">
17
+                <h3>Search this forum:</h3>
18
+                <form class="search_form" name="forum" action="forums.php" method="get">
19
+                    <table cellpadding="6" cellspacing="1" border="0" class="layout border">
20
+                        <tr>
21
+                            <td>
22
+                                <input type="hidden" name="action" value="search" />
23
+                                <input type="hidden" name="forums[]" value="{{ forum.id }}" />
24
+                                <strong>Search for:</strong>
25
+                            </td>
26
+                            <td>
27
+                                <input type="search" id="searchbox" name="search" size="70" />
28
+                            </td>
29
+                        </tr>
30
+                        <tr>
31
+                            <td><strong>Search in:</strong></td>
32
+                            <td>
33
+                                <input type="radio" name="type" id="type_title" value="title" checked="checked" />
34
+                                <label for="type_title">Titles</label>
35
+                                <input type="radio" name="type" id="type_body" value="body" />
36
+                                <label for="type_body">Post bodies</label>
37
+                            </td>
38
+                        </tr>
39
+                        <tr>
40
+                            <td><strong>Posted by:</strong></td>
41
+                            <td><input type="search" id="username" name="user" placeholder="Username" size="70" /></td>
42
+                        </tr>
43
+                        <tr>
44
+                            <td colspan="2" style="text-align: center;">
45
+                                <input type="submit" name="submit" value="Search" />
46
+                            </td>
47
+                        </tr>
48
+                    </table>
49
+                </form>
50
+                <br />
51
+            </div>
52
+        </div>
53
+    </div>

+ 40
- 0
templates/forum/main.twig View File

@@ -0,0 +1,40 @@
1
+{% if seen == 1 %}
2
+<a name="{{ category_id }}"></a>
3
+<h3>{{ category }}</h3>
4
+<table class="forum_index m_table">
5
+    <tr class="colhead">
6
+        <td style="width: 2%;"></td>
7
+        <td class="m_th_left" style="width: 25%;">Forum</td>
8
+        <td>Last Post</td>
9
+        <td class="m_th_right" style="width: 7%;">Topics</td>
10
+        <td class="m_th_right" style="width: 7%;">Posts</td>
11
+    </tr>
12
+{% endif %}
13
+<tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
14
+    <td class="td_read {{ icon_class }} {{ tooltip }}" title="{{ icon_class|replace({'_': ' '})|ucfirstall }}"></td>
15
+    <td class="td_forum">
16
+        <h4 class="min_padding">
17
+            <a class="{{ tooltip }}" href="forums.php?action=viewforum&amp;forumid={{ forum_id }}" title="{{ description }}">{{ name }}</a>
18
+        </h4>
19
+    </td>
20
+{% if not threads %}
21
+    <td class="td_latest">
22
+        There are no topics here.{% if creator %} <a href="forums.php?action=new&amp;forumid={{ forum_id }}">Create one!</a>{% endif %}
23
+    </td>
24
+{% else %}
25
+    <td class="td_latest">
26
+        <span style="float: left;" class="last_topic">
27
+            <a href="forums.php?action=viewthread&amp;threadid={{ id }}" class="tooltip" data-title-plain="{{ title }}"{%
28
+                if title != cut_title %} title="{{ title }}"{% endif %}>{{ cut_title }}</a>
29
+        </span>
30
+{% if is_read %}
31
+        <span style="float: left;" class="{{ tooltip }} last_read" title="Jump to last read">
32
+            <a href="forums.php?action=viewthread&amp;threadid={{ id }}&amp;page={{ last_read_page }}#post{{ last_read_post }}"></a>
33
+        </span>
34
+{% endif %}
35
+        <span style="float: right;" class="last_poster">by {{ last_post_user|raw }} {{ last_post_diff|raw }}</span>
36
+    </td>
37
+{% endif %}
38
+    <td class="td_topic_count number_column m_td_right">{{ num_topics|number_format }}</td>
39
+    <td class="td_post_count number_column m_td_right">{{ num_posts|number_format }}</td>
40
+</tr>

+ 106
- 0
templates/forum/new-thread.twig View File

@@ -0,0 +1,106 @@
1
+{% from 'macro/form.twig' import checked %}
2
+<div class="thin">
3
+    <h2><a href="forums.php">Forums</a> &rsaquo; <a href="forums.php?action=viewforum&amp;forumid={{ id }}">{{ name }}</a> &rsaquo; <span id="newthreadtitle">New Thread</span></h2>
4
+    <div class="hidden" id="newthreadpreview">
5
+        <div class="linkbox">
6
+            <div class="center">
7
+                <a href="#" onclick="return false;" class="brackets">Report thread</a>
8
+                <a href="#" onclick="return false;" class="brackets">{{ is_subbed ? 'Unsubscribe' : 'Subscribe' }}</a>
9
+            </div>
10
+        </div>
11
+{% if can.create_poll %}
12
+        <div class="box thin clear hidden" id="pollpreview">
13
+            <div class="head colhead_dark"><strong>Poll</strong> <a href="#" onclick="$('#threadpoll').gtoggle(); return false;" class="brackets">View</a></div>
14
+            <div class="pad" id="threadpoll">
15
+                <p><strong id="pollquestion"></strong></p>
16
+                <div id="pollanswers"></div>
17
+                <br /><input type="radio" name="vote" id="answer_0" value="0" /> <label for="answer_0">Blank&#8202;&mdash;&#8202;Show the results!</label><br /><br />
18
+                <input type="button" style="float: left;" value="Vote" />
19
+            </div>
20
+        </div>
21
+{% endif %}
22
+        <table class="forum_post box vertical_margin" style="text-align: left;">
23
+            <colgroup>
24
+{% if can.see_avatars %}
25
+                <col class="col_avatar" />
26
+{% endif %}
27
+                <col class="col_post_body" />
28
+            </colgroup>
29
+            <tr class="colhead_dark">
30
+                <td colspan="{{ can.see_avatars ? 2 : 1 }}">
31
+                    <span style="float: left;"><a href="#newthreadpreview">#XXXXXX</a> by <strong>{{ user_id|user_full }}</strong>
32
+                    Just now
33
+                    </span>
34
+                    <span id="barpreview" style="float: right;">
35
+                        <a href="#newthreadpreview" class="brackets">Report</a>
36
+                        &nbsp;
37
+                        <a href="#">&uarr;</a>
38
+                    </span>
39
+                </td>
40
+            </tr>
41
+            <tr>
42
+{% if can.see_avatars %}
43
+                <td class="avatar" valign="top">
44
+                    {{ avatar|raw }}
45
+                </td>
46
+{% endif %}
47
+                <td class="body" valign="top">
48
+                    <div id="contentpreview" style="text-align: left;"></div>
49
+                </td>
50
+            </tr>
51
+        </table>
52
+    </div>
53
+    <div class="box pad">
54
+        <form class="create_form" name="forum_thread" action="" id="newthreadform" method="post">
55
+            <input type="hidden" name="action" value="new" />
56
+            <input type="hidden" name="auth" value="{{ auth }}" />
57
+            <input type="hidden" name="forum" value="{{ id }}" />
58
+            <table id="newthreadtext" class="layout">
59
+                <tr>
60
+                    <td class="label">Title:</td>
61
+                    <td><input id="title" class="required" type="text" name="title" style="width: 98%;" /></td>
62
+                </tr>
63
+                <tr>
64
+                    <td class="label">Body:</td>
65
+                    <td><textarea id="posttext" class="required" style="width: 98%;" onkeyup="resize('posttext');" name="body" cols="90" rows="8"></textarea></td>
66
+                </tr>
67
+                <tr>
68
+                    <td></td>
69
+                    <td>
70
+                        <input id="subscribebox" type="checkbox" name="subscribe"{{ checked(is_subbed) }} onchange="$('#subscribeboxpreview').raw().checked=this.checked;" />
71
+                        <label for="subscribebox">Subscribe to topic</label>
72
+                    </td>
73
+                </tr>
74
+{% if can.create_poll %}
75
+                <tr>
76
+                    <td colspan="2" class="center">
77
+                        <strong>Poll Settings</strong>
78
+                        <a href="#" onclick="$('#poll_question, #poll_answers').gtoggle(); return false;" class="brackets">View</a>
79
+                    </td>
80
+                </tr>
81
+                <tr id="poll_question" class="hidden">
82
+                    <td class="label">Question:</td>
83
+                    <td><input type="text" name="question" id="pollquestionfield" class="required" style="width: 98%;" /></td>
84
+                </tr>
85
+                <tr id="poll_answers" class="hidden">
86
+                    <td class="label">Answers:</td>
87
+                    <td id="answer_block">
88
+                        <input type="text" name="answers[]" class="required" style="width: 90%;" />
89
+                        <a href="#" onclick="AddAnswerField();return false;" class="brackets">+</a>
90
+                        <a href="#" onclick="RemoveAnswerField();return false;" class="brackets">&minus;</a>
91
+                    </td>
92
+                </tr>
93
+{% endif %}
94
+            </table>
95
+            <div id="subscribediv" class="hidden">
96
+                <input id="subscribeboxpreview" type="checkbox" name="subscribe"{{ checked(is_subbed) }} />
97
+                <label for="subscribebox">Subscribe to topic</label>
98
+            </div>
99
+            <div id="buttons" class="center">
100
+                <input type="button" value="Preview" onclick="Newthread_Preview(1);" id="newthreadpreviewbutton" />
101
+                <input type="button" value="Editor" onclick="Newthread_Preview(0);" id="newthreadeditbutton" class="hidden" />
102
+                <input type="submit" class="submit" id="submit_button" value="Create thread" />
103
+            </div>
104
+        </form>
105
+    </div>
106
+</div>

+ 3
- 0
templates/forum/request-edit.twig View File

@@ -0,0 +1,3 @@
1
+[user]{{ username }}[/user] has submitted an editing request for: [url={{ url }}]{{ name }}[/url].
2
+
3
+[quote=Comments]{{ details }}[/quote]

+ 20
- 0
templates/forum/toc.twig View File

@@ -0,0 +1,20 @@
1
+<tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
2
+    <td class="td_read {{ icon_class }} {{ tooltip }}" title="{{ icon_class|replace({'_': ' '})|ucfirstall }}"></td>
3
+    <td class="td_latest">
4
+        <span style="float: left;" class="last_topic">
5
+            <strong>
6
+                <a href="forums.php?action=viewthread&amp;threadid={{ id }}" class="tooltip" data-title-plain="{{ title }}"{%
7
+                    if title != cut_title %} title="{{ title }}"{% endif %}>{{ cut_title }}</a>
8
+            </strong>
9
+            {{ page_links|raw }}
10
+        </span>
11
+{% if is_read %}
12
+        <span style="float: left;" class="{{ tooltip }} last_read" title="Jump to last read">
13
+            <a href="forums.php?action=viewthread&amp;threadid={{ id }}&amp;page={{ last_read_page }}#post{{ last_read_post }}"></a>
14
+        </span>
15
+{% endif %}
16
+        <span style="float: right;" class="last_poster">by {{ last_post_user|raw }} {{ last_post_diff|raw }}</span>
17
+    </td>
18
+    <td class="td_replies number_column m_td_right">{{ replies|number_format }}</td>
19
+    <td class="td_author">{{ author|raw }}</td>
20
+</tr>

+ 48
- 0
templates/forum/warn.twig View File

@@ -0,0 +1,48 @@
1
+<div class="thin">
2
+    <div class="header">
3
+        <h2>Warning <a href="user.php?id={{ user.id }}">{{ user.username }}</a></h2>
4
+    </div>
5
+    <div class="thin box pad">
6
+        <form class="send_form" name="warning" action="" onsubmit="quickpostform.submit_button.disabled = true;" method="post">
7
+            <input type="hidden" name="forumid" value="{{ form_id }}" />
8
+            <input type="hidden" name="auth" value="{{ auth }}" />
9
+            <input type="hidden" name="postid" value="{{ post_id }}" />
10
+            <input type="hidden" name="userid" value="{{ user.id }}" />
11
+            <input type="hidden" name="action" value="take_warn" />
12
+            <table class="layout" align="center">
13
+                <tr>
14
+                    <td class="label">Reason:</td>
15
+                    <td>
16
+                        <input type="text" name="reason" size="60" />
17
+                    </td>
18
+                </tr>
19
+                <tr>
20
+                    <td class="label">Length:</td>
21
+                    <td>
22
+                        <select name="length">
23
+                            <option value="verbal">Verbal</option>
24
+                            <option value="1">1 week</option>
25
+                            <option value="2">2 weeks</option>
26
+                            <option value="4">4 weeks</option>
27
+                            <option value="8">8 weeks</option>
28
+                        </select>
29
+                    </td>
30
+                </tr>
31
+                <tr>
32
+                    <td class="label">Private message:<br />(optional)</td>
33
+                    <td>
34
+                        <textarea id="message" style="width: 95%;" tabindex="1" onkeyup="resize('message');" name="privatemessage" cols="90" rows="4"></textarea>
35
+                    </td>
36
+                </tr>
37
+                <tr>
38
+                    <td class="label">Edit post:</td>
39
+                    <td>
40
+                        <textarea id="body" style="width: 95%;" tabindex="1" onkeyup="resize('body');" name="body" cols="90" rows="8">{{ body }}</textarea>
41
+                        <br />
42
+                        <input type="submit" id="submit_button" value="Warn user" tabindex="1" />
43
+                    </td>
44
+                </tr>
45
+            </table>
46
+        </form>
47
+    </div>
48
+</div>

+ 23
- 0
templates/inbox/compose.twig View File

@@ -0,0 +1,23 @@
1
+<div class="thin">
2
+    <div class="header">
3
+        <h2>Send a message to <a href="user.php?id={{ toid }}">{{ username }}</a></h2>
4
+    </div>
5
+    <form class="send_form" name="message" action="inbox.php" method="post" id="messageform">
6
+        <div class="box pad">
7
+            <input type="hidden" name="action" value="takecompose" />
8
+            <input type="hidden" name="toid" value="{{ toid }}" />
9
+            <input type="hidden" name="auth" value="{{ auth }}" />
10
+            <div id="quickpost">
11
+                <h3>Subject</h3>
12
+                <input type="text" class="required" name="subject" size="95" value="{{ subject }}" /><br />
13
+                <h3>Body</h3>
14
+                <textarea id="body" class="required" name="body" cols="95" rows="10" onkeyup="resize('body')">{{ body }}</textarea>
15
+            </div>
16
+            <div id="preview" class="hidden"></div>
17
+            <div id="buttons" class="center">
18
+                <input type="button" value="Preview" onclick="Quick_Preview();" />
19
+                <input type="submit" value="Send message" />
20
+            </div>
21
+        </div>
22
+    </form>
23
+</div>

+ 168
- 0
templates/index/private-header.twig View File

@@ -0,0 +1,168 @@
1
+{% macro active(t) -%}
2
+    {%- if t %} class="active"{% endif -%}
3
+{% endmacro %}
4
+{% macro active_class(t) %}
5
+    {%- if t %} active{% endif -%}
6
+{% endmacro -%}
7
+{% set stats = user.activityStats -%}
8
+<meta name="viewport" content="width=device-width" />
9
+</head>
10
+<body id="{% if document == 'collages' %}collage{% else %}{{ document }}{% endif %}">
11
+<input id="extracb1" class="hidden" type="checkbox">
12
+<input id="extracb2" class="hidden" type="checkbox">
13
+<input id="extracb3" class="hidden" type="checkbox">
14
+<input id="extracb4" class="hidden" type="checkbox">
15
+<input id="extracb5" class="hidden" type="checkbox">
16
+<div id="wrapper">
17
+<h1 class="hidden">{{ constant('SITE_NAME') }}</h1>
18
+<div id="header">
19
+    <div id="logo"><a href="index.php"></a></div>
20
+    <div id="userinfo">
21
+    <ul id="userinfo_username">
22
+        <li id="nav_userinfo" {{ _self.active(document == 'user' and request.id == user.id) }}>
23
+            <a href="user.php?id={{ user.id }}" class="username">{{ user.username }}</a>
24
+        </li>
25
+        <li id="nav_userclass">
26
+            <span class="hidden userclass">{{ user_class }}</span>
27
+        </li>
28
+        <li id="nav_useredit" class="brackets{{ _self.active_class(document == 'user' and action =='edit') }}">
29
+            <a href="user.php?action=edit&amp;userid={{ user.id }}">Edit</a>
30
+        </li>
31
+        <li id="nav_logout" class="brackets">
32
+            <a href="logout.php?auth={{ auth }}">Logout</a>
33
+        </li>
34
+    </ul>
35
+    <ul id="userinfo_major">
36
+        <li id="nav_upload" class="brackets{{ _self.active_class(document == 'upload') }}">
37
+            <a href="upload.php" title="Upload">Upload</a>
38
+        </li>
39
+        <li id="nav_bonus" class="brackets{{ _self.active_class(document == 'user' and action == 'bonus') }}">
40
+            <a href="bonus.php" class='tooltip' title="BP/hour: {{
41
+                stats.BonusPointsPerHour|number_format(3) }}">Bonus ({{ stats.BonusPoints|number_format }})</a>
42
+        </li>
43
+        <li id="nav_invite" class="brackets{{ _self.active_class(document == 'user' and action == 'invite') }}">
44
+            <a href="user.php?action=invite" class='tooltip' title="Invite a friend!">Invite
45
+            {% if user.permitted('site_send_unlimited_invites') %} (&infin;){% elseif user.inviteCount %} ({{ user.inviteCount }}){% endif %}</a>
46
+        </li>
47
+        <li id="nav_donate" class="brackets{{ _self.active_class(document == 'donate') }}">
48
+            <a href="donate.php" class='tooltip' title="Donate">Donate ({{ dono_target }}%)</a>
49
+        </li>
50
+    </ul>
51
+    <ul id="userinfo_stats">
52
+        <li id="stats_seeding">
53
+            <a href="torrents.php?type=seeding&amp;userid={{ user.id }}">Up</a>:
54
+            <span class="stat tooltip" title="{{ stats.BytesUploaded|octet_size(5) }}">{{ stats.BytesUploaded|octet_size }}</span>
55
+        </li>
56
+        <li id="stats_leeching">
57
+            <a href="torrents.php?type=leeching&amp;userid={{ user.id }}">Down</a>:
58
+            <span class="stat tooltip" title="{{ stats.BytesDownloaded|octet_size(5) }}">{{ stats.BytesDownloaded|octet_size }}</span>
59
+        </li>
60
+        <li id="stats_ratio">
61
+            Ratio: <span class="stat">{{ ratio(stats.BytesUploaded, stats.BytesDownloaded) }}</span>
62
+        </li>
63
+{% if required_ratio > 0 %}
64
+        <li id="stats_required">
65
+            <a href="rules.php?p=ratio">Required</a>:
66
+            <span class="stat tooltip" title="{{ required_ratio|number_format(5) }}">{{ required_ratio|number_format(2) }}</span>
67
+        </li>
68
+{% endif %}
69
+{% if user.tokenCount %}
70
+        <li id="fl_tokens">
71
+            <a href="wiki.php?action=article&amp;id=57">Tokens</a>:
72
+            <span class="stat">
73
+                <a href="userhistory.php?action=token_history&amp;userid={{ user.id }}">{{ user.tokenCount|number_format }}</a>
74
+            </span>
75
+        </li>
76
+{% endif %}
77
+    </ul>
78
+    <ul id="userinfo_minor"{% if new_subs %} class="highlite"{% endif %}>
79
+{% for link in nav_links -%}
80
+        {{ link|raw }}
81
+{%- endfor %}
82
+    </ul>
83
+</div>
84
+
85
+<div id="menu">
86
+    <h4 class="hidden">Site Menu</h4>
87
+    <ul>
88
+        <li id="nav_index"{{    _self.active(document == 'index')    }}><a href="index.php">Home</a> </li>
89
+        <li id="nav_torrents"{{ _self.active(document == 'torrents') }}><a href="torrents.php">Torrents</a> </li>
90
+        <li id="nav_collages"{{ _self.active(document == 'collages') }}><a href="collages.php">Collages</a> </li>
91
+        <li id="nav_requests"{{ _self.active(document == 'requests') }}><a href="requests.php">Requests</a> </li>
92
+        <li id="nav_forums"{{   _self.active(document == 'forums')   }}><a href="forums.php">Forums</a> </li>
93
+        <li id="nav_irc"{{      _self.active(document == 'chat')     }}><a href="wiki.php?action=article&amp;name=irc">IRC</a> </li>
94
+        <li id="nav_top10"{{    _self.active(document == 'top10')    }}><a href="top10.php">Top 10</a> </li>
95
+        <li id="nav_rules"{{    _self.active(document == 'rules')    }}><a href="rules.php">Rules</a> </li>
96
+        <li id="nav_wiki"{{     _self.active(document == 'wiki')     }}><a href="wiki.php">Wiki</a> </li>
97
+        <li id="nav_staff"{{    _self.active(document == 'staff')    }}><a href="staff.php" title="Staff">Staff</a> </li>
98
+    </ul>
99
+</div>
100
+
101
+{% if alert_list or action_list %}
102
+<div id="alerts">
103
+    {% if alert_list %}
104
+    <div class="alertbar">{{ alert_list|join(' &sdot; ')|raw }}</div>
105
+    {% endif %}
106
+    {% if action_list %}
107
+    <div class="alertbar blend">{{ action_list|join(' &sdot; ')|raw }}</div>
108
+    {% endif %}
109
+</div>
110
+{% endif %}
111
+
112
+<div id="searchbars">
113
+    <ul>
114
+    <li id="searchbar_torrents">
115
+        <span class="hidden">Torrents: </span>
116
+        <form class="search_form" name="torrents" action="torrents.php" method="get">
117
+{% if advanced_search %}
118
+            <input type="hidden" name="action" value="advanced" />
119
+{% endif %}
120
+            <input id="torrentssearch" value="Torrents" placeholder="Torrents" type="text" name="
121
+                {%- if advanced_search %}groupname{% else %}searchstr{% endif -%}
122
+                " size="17" spellcheck="false" accesskey="t" />
123
+        </form>
124
+    </li>
125
+    <li id="searchbar_artists">
126
+        <span class="hidden">Artist: </span>
127
+        <form class="search_form" name="artists" action="artist.php" method="get">
128
+            <input id="artistsearch"
129
+                {%- if user.hasAutocomplete('search') %} data-gazelle-autocomplete="true" {% else %} {% endif -%}
130
+                value="Artists" placeholder="Artists" type="text" name="artistname" size="17" spellcheck="false" accesskey="a" />
131
+        </form>
132
+    </li>
133
+    <li id="searchbar_collages">
134
+        <span class="hidden">Collage: </span>
135
+        <form class="search_form" name="artists" action="collage.php" method="get">
136
+            <input id="collagesearch" value="Collages" placeholder="Collage" type="text" name="search" size="17" spellcheck="false" accesskey="c" />
137
+        </form>
138
+    </li>
139
+    <li id="searchbar_requests">
140
+        <span class="hidden">Requests: </span>
141
+        <form class="search_form" name="requests" action="requests.php" method="get">
142
+            <input id="requestssearch" value="Requests" placeholder="Requests" type="text" name="search" size="17" spellcheck="false" accesskey="r" />
143
+        </form>
144
+    </li>
145
+    <li id="searchbar_forums">
146
+        <span class="hidden">Forums: </span>
147
+        <form class="search_form" name="forums" action="forums.php" method="get">
148
+            <input value="search" type="hidden" name="action" />
149
+            <input id="forumssearch" value="Forums" placeholder="Forums" type="text" name="search" size="17" accesskey="f" />
150
+        </form>
151
+    </li>
152
+    <li id="searchbar_log">
153
+        <span class="hidden">Log: </span>
154
+        <form class="search_form" name="log" action="log.php" method="get">
155
+            <input id="logsearch" value="Log" placeholder="Log" type="text" name="search" size="17" accesskey="l" />
156
+        </form>
157
+    </li>
158
+    <li id="searchbar_users">
159
+        <span class="hidden">Users: </span>
160
+        <form class="search_form" name="users" action="user.php" method="get">
161
+            <input type="hidden" name="action" value="search" />
162
+            <input id="userssearch" value="Users" placeholder="Users" type="text" name="search" size="20" spellcheck="false" accesskey="u" />
163
+        </form>
164
+    </li>
165
+    </ul>
166
+</div>
167
+</div>
168
+<div id="content">

+ 0
- 0
templates/index/private-main.twig View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save