]>
Commit | Line | Data |
---|---|---|
43f0b189 DC |
1 | class QuarantineView extends Component { |
2 | constructor(config = {}) { | |
3 | config.tpl = config.tpl || ` | |
4 | <div class="view view-quarantine"> | |
5 | <div data-name="quarantine-list" class="page"> | |
6 | <div class="navbar"> | |
7 | <div class="navbar-inner"> | |
8 | <div class="left"> | |
f07b75b0 TL |
9 | <img class="logo-navbar" style="padding: 0 10px" |
10 | src="pve2/images/logo-128.png" height=32 /> | |
43f0b189 DC |
11 | </div> |
12 | <div class="title">Mail Gateway</div> | |
13 | </div> | |
14 | </div> | |
15 | <div class="settings-form elevation-5 fab-morph-target"> | |
a827641e | 16 | <div class="block-title block-title-medium">` + gettext("Range") + `</div> |
43f0b189 DC |
17 | <div class="list no-hairlines-md"> |
18 | <ul> | |
19 | <li class="item-content item-input"> | |
20 | <div class="item-inner"> | |
fbc1a05b | 21 | <div class="item-title item-label">` + gettext("Since") + `</div> |
43f0b189 DC |
22 | <div class="item-input-wrap"> |
23 | <input type="date" name="from" placeholder="from" required validate> | |
24 | </div> | |
25 | </div> | |
26 | </li> | |
27 | <li class="item-content item-input"> | |
28 | <div class="item-inner"> | |
fbc1a05b | 29 | <div class="item-title item-label">` + gettext("Until") + `</div> |
43f0b189 DC |
30 | <div class="item-input-wrap"> |
31 | <input type="date" name="to" placeholder="to" required validate> | |
32 | </div> | |
33 | </div> | |
34 | </li> | |
35 | </ul> | |
a827641e | 36 | <a class="button fab-close range-form">` + gettext("OK") + `</a> |
43f0b189 DC |
37 | </div> |
38 | </div> | |
39 | <div class="fab fab-morph fab-right-bottom" data-morph-to=".settings-form"> | |
40 | <a href="#"> | |
41 | <i class="icon f7-icons ios-only">calendar</i> | |
42 | <i class="icon material-icons md-only">date_range</i> | |
43 | </a> | |
44 | </div> | |
45 | <div class="toolbar subscription toolbar-hidden toolbar-bottom"> | |
46 | <div class="toolbar-inner"> | |
47 | <a class="button subscription"> | |
48 | <i class="icon f7-icons ios-only color-yellow">alert</i> | |
49 | <i class="icon material-icons md-only color-yellow">warning</i> | |
50 | <span class="subscription-text"> | |
a827641e | 51 | ` + gettext("No valid subscription") + ` |
43f0b189 DC |
52 | </span> |
53 | </a> | |
54 | </div> | |
55 | </div> | |
56 | <div class="page-content ptr-content"> | |
57 | <div class="ptr-preloader"> | |
58 | <div class="preloader"></div> | |
59 | <div class="ptr-arrow"></div> | |
60 | </div> | |
61 | <div class="list virtual-list"></div> | |
62 | </div> | |
63 | </div> | |
64 | </div>`; | |
65 | config.itemTemplate = config.itemTemplate || ` | |
66 | <li class="swipeout"> | |
67 | <div class="swipeout-content"> | |
68 | <a href="/mail/{{id}}/" class="item-link item-content"> | |
69 | <div class="item-inner"> | |
70 | <div class="item-title"> | |
71 | <div class="item-header">{{escape from}}</div> | |
72 | {{escape subject}} | |
73 | </div> | |
74 | <div class="item-after">Score: {{js "this.spamlevel || 0"}}</div> | |
75 | </div> | |
76 | </a> | |
77 | </div> | |
78 | <div class="swipeout-actions-left"> | |
79 | <a href="/mail/{{id}}/deliver" class="color-green swipeout-close"> | |
80 | <i class="icon f7-icons ios-only">paper_plane</i> | |
81 | <i class="icon material-icons md-only">send</i> | |
a827641e | 82 | ` + gettext("Deliver") + ` |
43f0b189 DC |
83 | </a> |
84 | <a href="/mail/{{id}}/whitelist" class="swipeout-close"> | |
85 | <i class="icon f7-icons ios-only">check</i> | |
86 | <i class="icon material-icons md-only">check</i> | |
a827641e | 87 | ` + gettext("Whitelist") + ` |
43f0b189 DC |
88 | </a> |
89 | </div> | |
90 | <div class="swipeout-actions-right"> | |
91 | <a href="/mail/{{id}}/blacklist" class="color-orange swipeout-close"> | |
92 | <i class="icon f7-icons ios-only">close</i> | |
93 | <i class="icon material-icons md-only">close</i> | |
a827641e | 94 | ` + gettext("Blacklist") + ` |
43f0b189 DC |
95 | </a> |
96 | <a href="/mail/{{id}}/delete" class="color-red swipeout-close"> | |
97 | <i class="icon f7-icons ios-only">trash</i> | |
98 | <i class="icon material-icons md-only">delete</i> | |
a827641e | 99 | ` + gettext("Delete") + ` |
43f0b189 DC |
100 | </a> |
101 | </div> | |
102 | </li>`; | |
103 | config.dividerTemplate = config.dividerTemplate || | |
104 | '<li class="item-divider">{{group}}</li>'; | |
105 | super(config); | |
106 | ||
107 | var me = this; | |
108 | ||
109 | me._compiledItemTemplate = Template7.compile(me.config.itemTemplate); | |
110 | me._compiledDividerTemplate = Template7.compile(me.config.dividerTemplate); | |
111 | me.skelTpl = ` | |
112 | <li class="skeleton-text skeleton-effect-fade"> | |
113 | <a href="#" class="item-content item-link"> | |
114 | <div class="item-inner"> | |
115 | <div class="item-title"> | |
116 | <div class="item-header">_______________________</div> | |
117 | ____ ______ __ _______ ____ _______ _______ ___ | |
118 | </div> | |
119 | <div class="item-after">Score: 15</div> | |
120 | </div> | |
121 | </a> | |
122 | </li>`; | |
123 | me.skelDividerTpl = '<li class="item-divider skeleton-text">____-__-__</li>'; | |
124 | me.setEndtime(new Date()); | |
125 | let startdate = new Date(); | |
126 | startdate.setDate(startdate.getDate() - 7); | |
127 | me.setStarttime(startdate); | |
128 | ||
129 | // add to dom | |
130 | $$(me.config.target || '#app').append(me.getEl()); | |
131 | ||
132 | $$(document).on('page:init', '.page[data-name=quarantine-list]', (e, page) => { | |
133 | me.vList = app.virtualList.create({ | |
134 | el: '.virtual-list', | |
135 | items: [], | |
136 | renderItem: function(item) { | |
137 | return me._renderItem(item); | |
138 | }, | |
7a0d8540 DC |
139 | height: function(item) { |
140 | return me._calculateHeight(item); | |
141 | }, | |
c87d46fb | 142 | emptyTemplate: '<div class="empty">No data in database</div>', |
43f0b189 DC |
143 | }); |
144 | ||
145 | // setup pull to refresh | |
f07b75b0 | 146 | $$('.ptr-content').on('ptr:refresh', (ev) => { |
43f0b189 DC |
147 | me.setItems([ |
148 | { skel: true, divider: true }, | |
149 | { skel: true }, | |
150 | { skel: true }, | |
151 | { skel: true }, | |
152 | { skel: true, divider: true }, | |
153 | { skel: true }, | |
154 | { skel: true }, | |
155 | { skel: true }, | |
156 | { skel: true }, | |
157 | { skel: true }, | |
158 | { skel: true }, | |
159 | { skel: true }, | |
160 | ]); | |
161 | me.load().then(data => { | |
162 | me.setItems(data, { | |
163 | sorter: { | |
164 | property: 'time', | |
165 | numeric: true, | |
c87d46fb | 166 | direction: 'DESC', |
43f0b189 | 167 | }, |
c87d46fb | 168 | grouperFn: (val) => PMG.Utils.unixToIso(val.time), |
43f0b189 DC |
169 | }); |
170 | }).catch(PMG.Utils.showError).then(() => { | |
f07b75b0 | 171 | ev.detail(); |
43f0b189 DC |
172 | }); |
173 | }); | |
174 | ||
175 | // process query parameters | |
176 | let { mail, action, date, username, ticket } = PMG.Utils.extractParams(); | |
177 | if (date) { | |
178 | me.setStarttime(date); | |
179 | } | |
180 | ||
181 | // setup range form | |
182 | $$('input[name=from]').val(PMG.Utils.unixToIso(me.starttime)); | |
183 | $$('input[name=to]').val(PMG.Utils.unixToIso(me.endtime)); | |
184 | ||
185 | $$('.fab').on('fab:close', () => { | |
186 | let fromChanged = me.setStarttime($$('input[name=from]').val()); | |
187 | let toChanged = me.setEndtime($$('input[name=to]').val()); | |
188 | if (fromChanged || toChanged) { | |
189 | app.ptr.refresh(); | |
190 | } | |
191 | }); | |
192 | ||
193 | // check login | |
194 | ||
195 | let loginInfo = { username, ticket }; | |
196 | let showPopup = (username && ticket) || !PMG.Utils.authOK(); | |
197 | me._loginScreen = new LoginScreen({ loginInfo }); | |
198 | ||
199 | me._loginScreen.open().then(data => { | |
200 | me._loginScreen.close(); | |
201 | PMG.Utils.setLoginInfo(data); | |
202 | return PMG.Utils.getSubscriptionInfo(); | |
c87d46fb | 203 | }).then(data => PMG.Utils.checkSubscription(data, showPopup)).then(data => { |
43f0b189 DC |
204 | app.ptr.refresh(); |
205 | if (mail) { | |
206 | let url = "/mail/" + mail + "/" + (action || ""); | |
207 | me._view.router.navigate(url); | |
208 | } | |
209 | }).catch(PMG.Utils.showError); | |
210 | }); | |
211 | ||
212 | me._view = app.views.create('.view-quarantine', { | |
213 | main: me.config.mainView !== undefined ? me.config.mainView : true, | |
214 | url: '/', | |
215 | pushState: true, | |
c87d46fb | 216 | pushStateAnimateOnLoad: true, |
43f0b189 DC |
217 | }); |
218 | } | |
219 | setStarttime(starttime) { | |
220 | var me = this; | |
221 | let date = starttime; | |
222 | if (!(starttime instanceof Date)) { | |
223 | // we assume an ISO string | |
f07b75b0 TL |
224 | if (starttime === '') { |
225 | return null; | |
43f0b189 DC |
226 | } |
227 | date = new Date(PMG.Utils.isoToUnix(starttime)*1000); | |
228 | } | |
229 | // starttime is at beginning of date | |
c87d46fb | 230 | date.setHours(0, 0, 0, 0); |
43f0b189 DC |
231 | let result = Math.round(date.getTime()/1000); |
232 | if (result !== me.starttime) { | |
233 | me.starttime = result; | |
234 | return true; | |
235 | } | |
c87d46fb | 236 | return false; |
43f0b189 DC |
237 | } |
238 | setEndtime(endtime) { | |
239 | var me = this; | |
240 | let date = endtime; | |
241 | if (!(endtime instanceof Date)) { | |
f07b75b0 TL |
242 | if (endtime === '') { |
243 | return null; | |
43f0b189 DC |
244 | } |
245 | // we assume an ISO string | |
246 | date = new Date(PMG.Utils.isoToUnix(endtime)*1000); | |
247 | } | |
248 | // endtime is at the end of the day | |
249 | date.setHours(23, 59, 59); | |
250 | let result = Math.round(date.getTime()/1000); | |
251 | if (result !== me.endtime) { | |
252 | me.endtime = result; | |
253 | return true; | |
254 | } | |
255 | return false; | |
256 | } | |
7a0d8540 DC |
257 | _calculateHeight(item) { |
258 | var me = this; | |
259 | ||
260 | let height = 48; // default | |
261 | ||
262 | if (typeof item === 'object') { | |
263 | let type = app.theme + '-' + (item.divider? "divider" : 'item'); | |
264 | switch (type) { | |
265 | case 'md-divider': | |
266 | height = 48; | |
267 | break; | |
268 | case 'md-item': | |
269 | height = 54; | |
270 | break; | |
271 | case 'ios-divider': | |
272 | height = 31; | |
273 | break; | |
274 | case 'ios-item': | |
275 | height = 53; | |
276 | break; | |
c87d46fb | 277 | default: |
7a0d8540 DC |
278 | } |
279 | } | |
280 | ||
281 | return height; | |
282 | } | |
43f0b189 DC |
283 | _renderItem(item) { |
284 | var me = this; | |
285 | ||
c87d46fb | 286 | if (typeof item === 'object') { |
43f0b189 DC |
287 | if (item.skel) { |
288 | return item.divider? me.skelDividerTpl : me.skelTpl; | |
289 | } else if (item.divider) { | |
290 | return me._compiledDividerTemplate(item); | |
291 | } else { | |
292 | return me._compiledItemTemplate(item); | |
293 | } | |
294 | } | |
295 | ||
296 | return item.toString(); | |
297 | } | |
298 | setItems(items, options) { | |
299 | var me = this; | |
300 | if (options && options.sorter) { | |
301 | if (options.sorter.sorterFn) { | |
302 | items.sort(options.sorter.sorterFn); | |
303 | } else { | |
304 | let prop = options.sorter.property; | |
305 | let numeric = options.sorter.numeric; | |
306 | let dir = options.sorter.direction === "ASC" ? 1 : -1; | |
c87d46fb | 307 | items.sort((a, b) => { |
43f0b189 DC |
308 | let result; |
309 | ||
310 | if (numeric) { | |
311 | result = a[prop] - b[prop]; | |
312 | } else { | |
c87d46fb | 313 | result = a[prop] === b[prop] ? 0 : a[prop] < b[prop] ? 1 : -1; |
43f0b189 DC |
314 | } |
315 | ||
316 | return result * dir; | |
317 | }); | |
318 | } | |
319 | } | |
320 | me.vList.replaceAllItems(items); | |
321 | if (options && options.grouperFn) { | |
322 | let lastgroup; | |
323 | let offset = 0; | |
324 | for (let i = 0; i+offset < items.length; i++) { | |
325 | let item = items[i+offset]; | |
326 | let curgroup = options.grouperFn(item); | |
f07b75b0 | 327 | if (curgroup !== lastgroup) { |
c87d46fb | 328 | me.vList.insertItemBefore(i+offset++, { |
43f0b189 | 329 | divider: true, |
c87d46fb | 330 | group: curgroup, |
43f0b189 DC |
331 | }); |
332 | lastgroup = curgroup; | |
333 | } | |
334 | } | |
335 | } | |
336 | } | |
337 | load() { | |
338 | var me = this; | |
339 | return new Promise(function(resolve, reject) { | |
340 | app.request({ | |
341 | url: '/api2/json/quarantine/spam', | |
342 | data: { | |
343 | starttime: me.starttime, | |
c87d46fb | 344 | endtime: me.endtime, |
43f0b189 DC |
345 | }, |
346 | dataType: 'json', | |
347 | success: (response, status, xhr) => { | |
348 | resolve(response.data); | |
349 | }, | |
350 | error: xhr => { | |
351 | reject(xhr); | |
c87d46fb | 352 | }, |
43f0b189 DC |
353 | }); |
354 | }); | |
355 | } | |
356 | } | |
357 |