1class ReportDuplicates { 2 constructor() { 3 } 4 data = []; 5 uniqueItems = new Set(); 6 duplicates = []; 7 collectData = async (payload) => { 8 this.data = [this.data, ...payload]; 9 this.detectDuplicates(payload) 10 } 11 detectDuplicates = async (payload) => { 12 const _this = this; 13 let duplicateCount = 0; 14 let currentDuplicates = []; 15 for (const item of payload) { 16 let isDuplicate = false; 17 const key = JSON.stringify(item); 18 if (this.uniqueItems.has(key)) { 19 isDuplicate = true; 20 this.duplicates.push(item); 21 currentDuplicates.push(item); 22 duplicateCount++; 23 } else { 24 this.uniqueItems.add(key); 25 } 26 } 27 if (duplicateCount > 0) { 28 console.log("Total duplicates", _this.duplicates); 29 console.log("current duplicates", currentDuplicates); 30 await _this.postReportToDiscord(currentDuplicates); 31 } 32 } 33 formatReportDiscord = async (responsePayload) => { 34 const embeds = []; 35 const payload = []; 36 for (const item of responsePayload) { 37 const image = new Image(); 38 image.src = `data:image/png;base64,${item.imgBase64}`; 39 console.log(image); 40 const embed = { 41 title: "duplicate", 42 thumbnail: { 43 url: `attachment://${image}`, 44 }, 45 fields: [ 46 { 47 name: "Ðвог", 48 value: item.firstname, 49 }, 50 { 51 name: "ÐÑÑ", 52 value: item.firstname, 53 }, 54 ] 55 /*image: { 56 url: `data:image/png;base64,${item.imgBase64}`, 57 }*/ 58 }; 59 embeds.push(embed); 60 } 61 for (const item of responsePayload) { 62 const arrItem = {}; 63 64 arrItem.url = item.url; 65 arrItem.firstname = item.firstname; 66 arrItem.lastname = item.lastname; 67 arrItem.type = item.type; 68 arrItem.age = item.age; 69 arrItem.sex = item.sex; 70 payload.push(arrItem); 71 } 72 return {payload, embeds} 73 } 74 postReportToDiscord = async (responsePayload) => { 75 const webhook = "https://discord.com/api/webhooks/1306877525414248522/jW0_TAMw7i5bdz0hkSDhqpcdj0LqI3ZLIP75fLy1g5akBjp6Z4ad4MC5ikJ2ljei4DFh" 76 await fetch(webhook, { 77 method: "POST", 78 headers: { 79 "Content-Type": "application/json" 80 }, 81 body: JSON.stringify({ 82 username: "Captain Hook", 83 avatar_url: "https://cdn.discordapp.com/embed/avatars/0.png", 84 content: `\`\`\`json\n${JSON.stringify(responsePayload, null, 2)}\n\`\`\``, 85 // content: `Duplicated items of police report`, 86 // embeds: embeds 87 // embeds: embeds, 88 }) 89 }) 90 .then(response => { 91 if (!response.ok){ 92 console.error(`Error sending message to Discord: ${response.statusText}`); 93 } 94 }) 95 .catch(error => { 96 console.error("Error sending message to Discord:", error); 97 }) 98 } 99} 100 101 102class Reporting { 103 constructor(elementId, config) { 104 this.elementId = elementId; 105 this.config = config; 106 this.paginationEnabled = config && config.paginationEnabled; 107 this.totalItems = config && config.totalItems; 108 this.requiredType = config && config.requiredType; 109 this.exceptType = config && config.exceptType; 110 this.currentPage = null; 111 this.autoScrollIntoView = config && config.autoScrollIntoView; 112 this.asapType = config && config.asapType; 113 this.customItem = config && config.customItem; 114 if (!elementId) 115 console.error("Expected elementId is not available") 116 this.init().then(r => { 117 }); 118 } 119 120 init = async () => { 121 let page = 1; 122 let size = 30; 123 if (this.config) { 124 if (this.config.page) 125 page = this.config.page; 126 if (this.config.size) 127 size = this.config.size; 128 } 129 await this.get_list(page, size); 130 await this.searchEvent(); 131 } 132 133 searchEvent = async () => { 134 try { 135 const searchButton = document.getElementById('search-button'); 136 const query = document.getElementById('search-query'); 137 searchButton.addEventListener("mouseup", e => { 138 if (query.value.trim() !== "") { 139 this.get_list(1, 30, query.value); 140 } else { 141 this.get_list(1, 30); 142 } 143 }) 144 } catch (e) { 145 console.warn("Error initializing search event", e); 146 } 147 } 148 149 render_item(row, index) { 150 if (this.customItem) 151 return this.customItem(row, index) 152 else 153 return ` 154 <li> 155 <div class="uk-height-1-1"> 156 <a class="wanted-item" href="#reporting-${this.asapType&&this.asapType}-modal-${index}" uk-toggle> 157 <div class="wanted-item__context"> 158 <div class="uk-child-width-1-2@m uk-child-width-1-1 uk-grid uk-grid-collapse"> 159 <div> 160 <div class="wanted-item__img"> 161 <img src="data:data:image/png;base64,${row.imgBase64}" alt="${row.firstname}" uk-cover> 162 </div> 163 </div> 164 <div> 165 <div class="surname">
166 <span>ÐÑÑг /ÑÑ /:</span> ${row.lastname} 167 </div> 168 <div class="givenname"> 169 <span>ÐÑÑ:</span> ${row.firstname} 170 </div> 171 <div class="age"> 172 <span>ÐаÑ:</span> ${row.age} 173 </div> 174 <div class="sex"> 175 <span>ХүйÑ:</span> ${row.sex} 176 </div> 177 </div> 178 </div> 179 </div> 180 <div class="wanted-item__info"> 181 <span>ÐÑдÑÑлÑл Ó©Ð³Ó©Ñ :</span> ${row.department} 182 </div> 183 <div class="wanted-item__info"> 184 <span>УÑаÑ:</span> ${row.phone_number} 185 </div> 186 </a> 187 </div> 188 </li> 189 `; 190 } 191 192 render_modal(row, index) { 193 const _this = this; 194 return ` 195 <div id="reporting-${_this.asapType&&_this.asapType}-modal-${index}" class="uk-modal-container" uk-modal> 196 <div class="uk-modal-dialog uk-modal-body uk-padding-remove"> 197 <button class="uk-modal-close-default" type="button" uk-close></button> 198<!-- <h2 class="uk-modal-title">Outside</h2>--> 199 <div class="wanted-item wanted-modal"> 200 <div class="wanted-item__context display-flex"> 201 <div class="uk-width-1-5@xl uk-width-1-4@l uk-width-1-3@m uk-width-1-2"> 202 <div class="wanted-item__img"> 203 <img src="data:data:image/png;base64,${row.imgBase64}" alt="${row.firstname}" uk-cover> 204 </div> 205 </div> 206 <div> 207 <div class="surname"> 208 <span>ÐÑÑг /ÑÑ /:</span> ${row.lastname} 209 </div> 210 <div class="givenname"> 211 <span>ÐÑÑ:</span> ${row.firstname} 212 </div> 213 <div class="age"> 214 <span>ÐаÑ:</span> ${row.age} 215 </div> 216 <div class="sex"> 217 <span>ХүйÑ:</span> ${row.sex} 218 </div> 219 </div> 220 </div> 221 <div class="uk-margin-medium-top" style="text-align: justify; font-size: 14px;"> 222 Танд ÑÐ½Ñ Ñ Ò¯Ð½Ð¸Ð¹ ÑÐ°Ð»Ð°Ð°Ñ Ó©Ð³Ó©Ñ Ð¼ÑдÑÑлÑл байгаа бол Ð´Ð¾Ð¾Ñ Ð±Ð°Ð¹ÑÐ»Ð°Ñ 223 <b>ÐÐÐÐÐÐÐÐ Ó¨ÐӨХ УТСÐÐÐ</b> Ñ Ð¾Ð»Ð±Ð¾Ð³Ð´Ð¾Ð¶ 224 Ñагдаагийн байгÑÑллагаÑай Ñ Ð°Ð¼ÑÑан Ð°Ð¶Ð¸Ð»Ð»Ð°Ñ Ñг Ñ Ò¯ÑÑе. 225 <br> 226 <br> 227 <p class="" style="text-align: center; margin: 5px; color:red"> 228 ÐÐÐТ Ð¥ÐÐ ÐÐÐС УРЬÐЧÐÐÐРСÐÐ ÐÐÐÐÐÐ¥ ТУХÐÐ ÐÐÐÐÐРУÐСЫРХУУÐÐÐС 229 </p> 230 <strong>35 дÑÐ³Ð°Ð°Ñ Ð·Ò¯Ð¹Ð».ÐÑÐ¼Ñ Ñ ÑÑÑг, зөÑÑлийн ÑÑÑ Ð°Ð¹ мÑдÑÑллийг иÑгÑдÑÑÑ ÑөлбөÑÑÑй Ð°Ð²Ð°Ñ </strong> 231 <p style="margin-top: 0;"> 232 35.1.ÐÑÐ¼Ñ Ñ ÑÑÑг, зөÑÑил үйлдÑÑ ÑÑÑ Ð±ÑлÑгÑж байгаа болон үйлдÑÑн ÑÑÑ Ð°Ð¹ мÑдÑÑллийг гÑÐ¼Ñ 233 Ñ ÑÑÑг, зөÑÑлийг Ñ Ñнан ÑÐ°Ð»Ð³Ð°Ñ ÑÑÑ Ð±Ò¯Ñ Ð¸Ð¹ байгÑÑллага иÑгÑдÑÑÑ ÑөлбөÑÑÑй Ð°Ð²Ñ Ð±Ð¾Ð»Ð½Ð¾. 234 <br> 235 35.2.ÐÑÐ¼Ñ Ñ ÑÑÑг, зөÑÑлийн ÑÑÑ Ð°Ð¹ мÑдÑÑллийг ÑөлбөÑÑÑй Ð°Ð²Ð°Ñ Ð°Ð¶Ð¸Ð»Ð»Ð°Ð³Ð°Ð°Ð½Ð´ ÐÓ©ÑÑил Ñалган 236 ÑийдвÑÑлÑÑ ÑÑÑ Ð°Ð¹ Ñ ÑÑлийн 6.2 дÑÐ³Ð°Ð°Ñ Ð·Ò¯Ð¹Ð», ÐÑүүгийн Ñ ÑÑÑг Ñ Ñнан ÑийдвÑÑлÑÑ ÑÑÑ Ð°Ð¹ Ñ ÑÑлийн 237 30.5 дÑÐ³Ð°Ð°Ñ Ð·Ò¯Ð¹Ð»Ð¸Ð¹Ð³ баÑимÑална. 238 <br> 239 35.3.ÐÑÐ¼Ñ Ñ ÑÑÑг, зөÑÑлийн Ñ ÑÑÑг бүÑÑгÑл, мөÑдөн ÑÐ°Ð»Ð³Ð°Ñ ÑÑÑ Ð±Ò¯Ñ Ð¸Ð¹ байгÑÑллага, албан 240 ÑÑÑаалÑан мÑдÑÑллийн нÑÑÑÑг Ñанд Ñ Ð°Ð´Ð³Ð°Ð»Ð¶, ÑааÑдлагаÑай бол мÑдÑÑлÑгÑийн аÑÑлгүй байдлÑг 241 Ñ Ð°Ð½Ð³Ð°Ñ Ð°Ñга Ñ ÑмжÑÑг Ð°Ð²Ð°Ñ Ò¯Ò¯ÑÑгÑÑй. 242 </p> 243 244 <br> 245 <p style="text-align: center;"> 246 <b>ÐÐÐÐÐÐÐÐ Ó¨ÐӨХ:
247 <span id="ctl00_ContentPlaceHolder1_phone">${row.phone_number}</span> 248 </b> 249 </p> 250 </div> 251 </div> 252 </div> 253 </div> 254 ` 255 } 256 257 renderPagination(page, size, totalPages) { 258 const paginationContainer = document.getElementById(`pagination-container-${this.elementId}`); 259 if (!paginationContainer) { 260 console.error("Pagination container element not found"); 261 return; 262 } 263 264 const maxPaginationItems = 5; // Maximum number of pagination items to display 265 266 // Calculate the starting and ending page numbers for the pagination 267 let startPage = Math.max(1, page - Math.floor(maxPaginationItems / 2)); 268 let endPage = Math.min(totalPages, startPage + maxPaginationItems - 1); 269 270 // Adjust the starting page if the ending page is at the maximum 271 startPage = Math.max(1, endPage - maxPaginationItems + 1); 272 273 // Create the pagination HTML 274 let paginationHTML = ` 275 <ul class="uk-pagination"> 276 <li class="pagination-item ${page === 1 ? 'disabled' : ''}"> 277 <a href="#" class="pagination-link" data-page="1">«</a> 278 </li> 279 `; 280 281 for (let i = startPage; i <= endPage; i++) { 282 paginationHTML += ` 283 <li class="pagination-item ${page === i ? 'uk-active' : ''}"> 284 <a href="#" class="pagination-link" data-page="${i}">${i}</a> 285 </li> 286 `; 287 } 288 289 paginationHTML += ` 290 <li class="pagination-item ${page === totalPages ? 'disabled' : ''}"> 291 <a href="#" class="pagination-link" data-page="${totalPages}">»</a> 292 </li> 293 </ul> 294 `; 295 296 // Set the pagination HTML to the container 297 paginationContainer.innerHTML = paginationHTML; 298 299 // Add event listeners to pagination links 300 const paginationLinks = paginationContainer.querySelectorAll('.pagination-link'); 301 paginationLinks.forEach(link => { 302 if (!link.classList.contains('disabled')) { 303 link.addEventListener('click', (event) => { 304 event.preventDefault(); 305 const newPage = parseInt(event.target.dataset.page); 306 const newOffset = (newPage - 1) * size; 307 this.get_list(newPage, size); 308 }); 309 } 310 }) 311 } 312 313 get_list = async (page, size, query) => { 314 const _this = this; 315 try { 316 const reportDuplicate = new ReportDuplicates(); 317 if (_this.autoScrollIntoView) 318 document.getElementById(_this.elementId).scrollIntoView({behavior: 'smooth'}); 319 const itemsTarget = document.getElementById(_this.elementId); 320 const wantedModalTarget = document.getElementById("wanted-modals-target"); 321 const missingModalTarget = document.getElementById("missing-modals-target"); 322 const violationModalTarget = document.getElementById("violation-modals-target") 323 const spinnerElement = document.createElement("div"); 324 spinnerElement.className = "spinner-container"; 325 spinnerElement.innerHTML = ` 326 <div class="spinner-overlay"></div> 327 <div style="display: flex; align-items: center; justify-content: center; width: 100%; min-height: 300px; background-color: #efefef"> 328 <i class="fas fa-spinner fa-spin" style="font-size: 36px;"></i> 329 </div>`; 330 331 itemsTarget.innerHTML = ''; // Clear the content before adding the spinner 332 itemsTarget.appendChild(spinnerElement); 333 let size1 = page; 334 let size2 = size; 335 if (page !== 1) 336 size1 = ((page * 30) + 1) - 30; 337 if (page !== 1) 338 size2 = ((page * 30) + 1); 339 let url = `/police/reporting?page=${size1}&size=${size}&asapType=${_this.asapType}` 340 if (query) 341 url += `&q=${query}`; 342 343 const response = await fetch(url, { 344 headers: { 345 "Accept": "application/json", 346 "Content-Type": "application/json", 347 } 348 }); 349 const data = await response.json(); 350 let html = ""; 351 let modalHTML = ""; 352 //formattedItem Ñг formattedItems ÑÑÑ Ð½Ñмж duplicate ÑÑÑÑ Ð¸Ð¹Ð³ илÑүүлÑÑ Ñд аÑиглана 353 const formattedItems = []; 354 if (data && data.asapPeople.length > 0) { 355 let index = 0; 356 for (let row of data.asapPeople) { 357 const formattedItem = {}; 358 //formattedItem Ñг duplicate ÑÑÑÑ Ð¸Ð¹Ð³ илÑүүлÑÑ Ñд аÑиглана 359 formattedItem.url = url; 360 formattedItem.firstname = row.firstname; 361 formattedItem.lastname = row.lastname; 362 formattedItem.type = row.type; 363 formattedItem.age = row.age; 364 formattedItem.sex = row.sex; 365 formattedItems.push(formattedItem); 366 367 html += _this.render_item(row, index); 368 modalHTML += _this.render_modal(row, index); 369 index++; 370 } 371 } else { 372 html = "No items found."; 373 } 374 console.log("formattedItems", formattedItems) 375 reportDuplicate.collectData(formattedItems); 376 itemsTarget.removeChild(spinnerElement); // Remove the spinner after the content is updated 377 itemsTarget.innerHTML = html; // Update the content with the loaded data 378 if (this.asapType === "missing") 379 missingModalTarget.innerHTML = modalHTML; 380 else if (this.asapType === "wanted") 381 wantedModalTarget.innerHTML = modalHTML; 382 else if (this.asapType === "violation") 383 violationModalTarget.innerHTML = modalHTML; 384 if (_this.paginationEnabled) 385 _this.renderPagination(page, size, Math.round((data.totalCount / 30))); // Call renderPagination here 386 if (_this.autoScrollIntoView) 387 document.getElementById(_this.elementId).scrollIntoView({behavior: 'smooth'}); 388 } catch (error) { 389 // Handle any error that occurred during the fetch request or data processing 390 console.error(error); 391 } 392 } 393}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.