Why are some chrome extensions ineffective at removing the CSP header in response? [duplicate]

I’m learning Chrome extension development and I’m trying to build a plugin that removes HTTP response headers (I know there are already plenty of these out there, but I just want to practice). However, I stumbled upon something interesting: when it comes to the CSP (Content-Security-Policy) header, this technique seems to fail on some websites. How do these sites manage to bypass my extension’s attempts to remove the CSP header? I’m just really curious about their approach.

I’ve been diving into Chrome extension development, mostly using these resources as my main references: declarativeNetRequest (V3) and webRequest (V2). I coded an extension to remove HTTP response headers, but I found it doesn’t work for certain URLs, like https://teams.live.com/v2/.

So, I tried out some extensions from the market, including Allow CSP and ModHeader. either of these extensions could remove the CSP header from https://teams.live.com/v2/.

I did some research, looking at questions like (Getting around X-Frame-Options DENY in a Chrome extension?), and tried both V2 and V3 APIs based on the answers there. The extension still wasn’t working as expected.

Especially with V2. I even printed the headers in the webRequest.onHeadersReceived listener after removing the CSP header, and the console showed that the response headers no longer contained the CSP. However, when I checked the DevTools, the CSP header was still there. I also ran some injected scripts to verify, and the CSP enforcement was indeed active.

I noticed that https://teams.live.com/v2/ uses a service worker, so I disabled it, but the issue persisted.

I’m using Chrome version 127.0.6533.72, and I’ve also tested with version 122.x, but the issue persisted.

I thought modifying response headers was a common task, but I’ve been stuck on this for days now. Am I missing something?

Telegram share with chats festure?

Hello guys please the ones who sre proficient with telegram API.

Im trying to initiate this kind pf ehare popup which lookslike its native to telegram from my fast API but no luck.

Do you have any ideas how it should work ?

I have been trying everything but i cant even find anything in telegrams docs

Thank you

telegram share with

ui-select not displaying selected value

I am using AngularJS with ui-select to create a dropdown for selecting a holding time period. The dropdown populates correctly and displays the options, but after I perform a search action and select an option, the selected value is not displayed in the input field.

<div class="col-lg-6 col-sm-12 col-xs-12">
  <div class="col-lg-4 col-xs-5">
    <label class="control-label"><strong>Holding Time Period : 
      </strong></label>
  </div>
  <div class="col-lg-4 col-xs-7">
    <!--<select name="procurementMode" ui-select2="dropDown" ng-model="search.HoldingTimePeriodId" data-placeholder="Select Holding Time Period" title="Select Holding Time Period">
    <option></option>
    <option ng-repeat="t in holdingTimePeriods" value="{{t.Id}}">{{t.Display}}</option>
    </select>-->
    <ui-select name="procurementMode" ng-model="search.HoldingTimePeriodId" theme="select2" style="width: 100% !important;">
      <ui-select-match allow-clear="true" placeholder="Select Holding Time Period" title="Select Holding Time Period">{{$select.selected.Display}}</ui-select-match>
      <ui-select-choices refresh-delay="1" repeat="t.Id as t in holdingTimePeriods | filter:$select.search">
      {{t.Display}}
      </ui-select-choices>
    </ui-select>
  </div>
</div>

holdingTimePeriod.png

JavaScript File

(function (window, angular, undefined) {
    'use strict';
    angular.module('angularModule.controllers').controller('searchempManagerCtrl', ['$scope', '$compile', '$window', 'ajaxCall', '$controller', 'checkPermissions', '$rootScope', 'permissionCheckService', 'emailManagerColumns', '$timeout', function ($scope, $compile, $window, ajaxCall, $controller, checkPermissions, $rootScope, permissionCheckService, emailManagerColumns, $timeout) {
        permissionCheckService.check('Email_Manager_View');
        //Injecting common useful values to the scope
        $controller('commonCtrl', { $scope: $scope });

        $scope.fromdate = "";
        $scope.enable = false;
        $scope.templateId = { Id: null };
        $scope.search = { OpeningStockSubmitted: null, DisclosureSubmitted: null, AnnualHoldingSubmitted: null, HoldingTimePeriodId: null, QuarterlyIntimationSubmitted: null, CompanyId: null, ClassId: null };
        
        $scope.gridConfig.getData = function (e) {

            $scope.search.RowsPerPage = $scope.reset ? 20 : e.data.pageSize;
            $scope.search.PageNumber = $scope.reset ? 1 : e.data.page;
            if (!isValidObject($scope.search.AsOfDateString)) {
                alertify.error("Please Select As Of Date");
                return;
            }
            $scope.search.HoldingTimePeriodId = $scope.search.HoldingTimePeriodId ? $scope.search.HoldingTimePeriodId.toString() : null;
            $scope.search.QuarterlyIntimationTimePeriodId = $scope.search.QuarterlyIntimationTimePeriodId ? $scope.search.QuarterlyIntimationTimePeriodId.toString() : null;
            $scope.search.CompanyId = $scope.search.CompanyId ? $scope.search.CompanyId.toString() : null;
            $scope.search.ClassId = $scope.search.ClassId ? $scope.search.ClassId.toString() : null;
            //$scope.search.HoldingTimePeriodId = $scope.search.HoldingTimePeriodId.toString();
            //$scope.search.QuarterlyIntimationTimePeriodId = $scope.search.QuarterlyIntimationTimePeriodId.toString();
            //$scope.search.CompanyId = $scope.search.CompanyId.toString();
            //$scope.search.ClassId = $scope.search.ClassId.toString();
            $rootScope.viewLoading = true;
            $scope.gridConfig.isLocalData = true;
            ajaxCall.post('/ETT/EmailManager/SearchEmployees', JSON.stringify({ emailManager: $scope.search }), false).then(function (data) {
                if (data.IsError) {
                    alertify.error(data.Message);
                    $rootScope.viewLoading = false;
                    return;
                }
                $scope.gridConfig.ds = $scope.formatData(data.SearchResults);
                $scope.gridConfig.dataCount = data.Count;
                $scope.count = data.Count;
                e.success({ data: $scope.gridConfig.ds, total: $scope.gridConfig.dataCount });
                $rootScope.viewLoading = false;
            });

        };
        $scope.getHoldingTimePeriodList = function () {
            ajaxCall.get('/TimePeriod/GetAllHoldingTimePeriods').then(function (data) {
                if (!isValidObject(data)) {
                    return;
                } else {
                    if (data.IsError) {
                        alertify.error(data.Message);
                    } else {
                        console.log('Holding Time Periods:', data.holdingTimePeriods);
                        $scope.holdingTimePeriods = data.holdingTimePeriods;
                    }
                }
            });
        }
        

        $scope.exportAllRecords = function (isExportAll) {
            $rootScope.viewLoading = true;
            if (!isExportAll) {
                getExportData_Kendo_GetFile(false, $scope.gridConfig.gridId, $scope.gridConfig.columns, undefined, undefined, undefined, true);
            }
            else {
                xhr_DownloadFile('/ETT/EmailManager/ExportToExcel?asOfDate=' + $scope.search.AsOfDateString + '&joiningDateTo=' + $scope.search.JoiningDateToString + '&joiningDateFrom=' + $scope.search.JoiningDateFromString + '&relievingDateAsOf=' + $scope.search.RelievingDateAsOfString + '&excludeRelieved=' + $scope.search.ExcludeRelieved + '&openingStockSubmitted=' + $scope.search.OpeningStockSubmitted + '&disclosureSubmitted=' +
                    $scope.search.DisclosureSubmitted + '&annualHoldingSubmitted=' + $scope.search.AnnualHoldingSubmitted + '&holdingTimePeriodId=' + $scope.search.HoldingTimePeriodId.toString() + '&quarterlyIntimationSubmitted=' + $scope.search.QuarterlyIntimationSubmitted + '&quarterlyIntimationTimePeriodId=' + $scope.search.QuarterlyIntimationTimePeriodId.toString() + '&companyId=' + $scope.search.CompanyId.toString() + '&classId=' + $scope.search.ClassId.toString(), 'GET');
            }
            $rootScope.viewLoading = false;
        }
        
        

    }]);
})(window, window.angular);

Expected Behavior:

After selecting an option, the selected value should be displayed in the ui-select input field.

Actual Behavior:

The selected value is not displayed in the ui-select input field after selection.

Reaction diffusion with shaders on WEBGL

I’m writing a reaction diffusion simulation with p5js based on a video and this tutorial. The code so far is this:

var vertSrc = `
#ifdef GL_ES
precision mediump float;
#endif

attribute vec3 aPosition;
attribute vec2 aTexCoord;

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

varying vec2 vTexCoord;

void main() {
    vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0);
    gl_Position = uProjectionMatrix * viewModelPosition;

    vTexCoord = aTexCoord;
}
`;

var fragSrc = `
#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D uTexture;
uniform vec2 uTexSize;

uniform float uDiffuRateA;
uniform float uDiffuRateB;
uniform float uFeedRate;
uniform float uKillRate;

varying vec2 vTexCoord;

vec2 laplacian(vec2 coord) {
    vec2 sum = vec2(0.0);

    mat3 kernel = mat3(
        0.05, 0.20, 0.05,
        0.20, -1.0, 0.20,
        0.05, 0.20, 0.05
    );

    for (int i = -1; i <= 1; i++) {
        for (int j = -1; j <= 1; j++) {
            vec2 offset = vec2(float(i), float(j)) / uTexSize;
            sum += texture2D(uTexture, coord + offset).rg * kernel[i+1][j+1];
        }
    }

    return sum;
}

void main() {
    vec4 color = texture2D(uTexture, vTexCoord);
    float A = color.r;
    float B = color.g;

    vec2 laplacianAB = laplacian(vTexCoord);

    float reaction = A * B * B;
    float feed = uFeedRate * (1.0 - A);
    float kill = (uKillRate + uFeedRate) * B;

    float dA = A + (uDiffuRateA * laplacianAB.r) - reaction + feed;
    float dB = B + (uDiffuRateB * laplacianAB.g) + reaction - kill;

    dA = clamp(dA, 0.0, 1.0);
    dB = clamp(dB, 0.0, 1.0);

    gl_FragColor = vec4(dA, dB, 0.0, 1.0);
}
`

var default_shader;
var cur_texture;
var buffer;

function preload() {
    default_shader = createShader(vertSrc, fragSrc);
}

function setup() {
    createCanvas(window.innerWidth, window.innerHeight, WEBGL);

    cur_texture = createFramebuffer({ channels: RGB, depth: false, textureFiltering: LINEAR });
    buffer = createFramebuffer({ channels: RGB, depth: false, textureFiltering: LINEAR });
    cur_texture.begin();
        background("#f00");
        fill("#0f0");
        circle(0, 0, 100);
    cur_texture.end();

    shader(default_shader);
    default_shader.setUniform("uTexSize", [cur_texture.width, cur_texture.height]);
    default_shader.setUniform("uDiffuRateA", 1.0);
    default_shader.setUniform("uDiffuRateB", 0.5);
    default_shader.setUniform("uFeedRate", 0.055);
    default_shader.setUniform("uKillRate", 0.062);

    noStroke();
}

function draw() {
    buffer.begin();
        background(0);
        default_shader.setUniform("uTexture", cur_texture);
        plane(width, height);
    buffer.end();

    let temp = cur_texture;
    cur_texture = buffer;
    buffer = temp;

    default_shader.setUniform("uTexture", cur_texture);
    plane(width, height);
}
html, body {
    margin: 0;
    padding: 0;
}

canvas {
    display: block;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.js"></script>
  </head>
</html>

Insted of interesting patterns I get a green ring. The result is similar to this other question, but I don’t think p5js has a RGBA32F format for the buffers.

Changing the parameters does produce different effects but none similar to what I was expecting. For example, setting uDiffuRateA to 2 eventually fills the screen with green.

Solana swap has a very low success rate

I am trying to do a simple swap on Solana block chain and I have tried both Alchemy and Quicknode but the success rate of my swap is very low.. 2 out of three times it fails and I cant even figure a way to properly log the reason ofthe failure

below is my script:

const axios = require('axios');
const dotenv = require('dotenv');
const { Connection, Keypair, sendAndConfirmRawTransaction, VersionedTransaction, ComputeBudgetProgram, Transaction, TransactionInstruction, TransactionMessage, PublicKey } = require('@solana/web3.js');
const winston = require('winston');
require('winston-daily-rotate-file');

dotenv.config();

const ALCHEMY_RPC_ENDPOINT = process.env.ALCHEMY_RPC_ENDPOINT; // Alchemy's RPC endpoint
const QUICKNODE_ENDPOINT = process.env.QUICKNODE_ENDPOINT; // QuickNode's endpoint for fetching priority fees
const WALLET_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY;
const SOL_AMOUNT = 0.3 * 1e9; // Amount of SOL to swap in lamports
const MAX_RETRIES = 1; // Maximum number of retries for transactions
const SLIPPAGE_BPS = 1000; // Slippage in basis points (3%)
const DEFAULT_PRIORITY_FEE = 50000; // Default priority fee in microLamports

// Set up Winston logger
const transport = new winston.transports.DailyRotateFile({
  filename: 'logs/application-%DATE%.log',
  datePattern: 'YYYY-MM-DD',
  zippedArchive: true,
  maxSize: '20m',
  maxFiles: '14d'
});

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ timestamp, level, message }) => `${timestamp} [${level}]: ${message}`)
  ),
  transports: [
    transport,
    new winston.transports.Console()
  ]
});

async function getQuote(inputMint, outputMint, amount, slippageBps) {
  const url = `https://quote-api.jup.ag/v6/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${slippageBps}`;
  logger.info(`Fetching quote from: ${url}`);

  try {
    const response = await axios.get(url);
    logger.info('Quote fetched successfully:', JSON.stringify(response.data));
    return response.data;
  } catch (error) {
    logger.error('Error fetching quote:', error.response?.data || error.message);
    return null;
  }
}

async function checkTransactionStatus(connection, txid) {
  try {
    const confirmation = await connection.confirmTransaction(txid, 'confirmed');
    logger.info(`Transaction confirmation response: ${JSON.stringify(confirmation)}`);
    if (confirmation.value.err) {
      logger.error(`Transaction failed with error: ${JSON.stringify(confirmation.value.err)}`);
      throw new Error(`Transaction failed with error: ${JSON.stringify(confirmation.value.err)}`);
    }
    return confirmation;
  } catch (error) {
    logger.error(`Transaction status check failed: ${error.message}`);
    throw new Error(`Transaction status check failed: ${error.message}`);
  }
}

async function simulateTransaction(connection, transaction) {
  try {
    const simulation = await connection.simulateTransaction(transaction);
    logger.info('Simulation result:', JSON.stringify(simulation));
    if (simulation.value.err) {
      logger.error('Simulation failed with error:', JSON.stringify(simulation.value.err));
      logger.error('Simulation logs:', JSON.stringify(simulation.value.logs));
      throw new Error(`Simulation failed with error: ${JSON.stringify(simulation.value.err)}`);
    }
    logger.info('Transaction simulation logs:', JSON.stringify(simulation.value.logs));
    return simulation.value.unitsConsumed;
  } catch (error) {
    logger.error(`Transaction simulation failed: ${error.message}`, { error: error });
    throw new Error(`Transaction simulation failed: ${error.message}`);
  }
}

async function executeSwap(quoteResponse, payer, connection, priorityFee, computeUnitLimit) {
  logger.info("Preparing to execute swap...");

  const postData = {
    quoteResponse: quoteResponse,
    userPublicKey: payer.publicKey.toString(),
    wrapAndUnwrapSol: true,
    priorityFee: priorityFee
  };

  try {
    const swapResponse = await axios.post('https://quote-api.jup.ag/v6/swap', postData, {
      headers: { 'Content-Type': 'application/json' }
    });

    logger.info('Swap API response:', JSON.stringify(swapResponse.data));

    const transactionBuffer = Buffer.from(swapResponse.data.swapTransaction, 'base64');
    const transaction = VersionedTransaction.deserialize(transactionBuffer);
    transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
    transaction.sign([payer]);

    const unitsConsumed = await simulateTransaction(connection, transaction);
    logger.info(`Units consumed by the transaction: ${unitsConsumed}`);

    logger.info("Sending transaction...");
    let txid = null;
    let attempt = 0;

    while (attempt < MAX_RETRIES) {
      try {
        txid = await sendAndConfirmRawTransaction(connection, transaction.serialize(), {
          skipPreflight: true,
          preflightCommitment: 'confirmed'
        });
        logger.info(`Transaction sent, ID: ${txid}`);
        const status = await checkTransactionStatus(connection, txid);
        logger.info(`Transaction status: ${JSON.stringify(status)}`);
        return txid;
      } catch (error) {
        logger.error(`Attempt ${attempt + 1} failed: ${error.message}`, { error: error });
        attempt++;
      }
    }

    throw new Error(`Swap failed after ${MAX_RETRIES} attempts.`);
  } catch (error) {
    logger.error('Swap execution failed:', error.response?.data || error.message);
    return null;
  }
}

async function getSimulationUnits(connection, instructions, payer) {
  const testInstructions = [
    ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
    ...instructions,
  ];

  const testVersionedTxn = new VersionedTransaction(
    new TransactionMessage({
      instructions: testInstructions,
      payerKey: payer,
      recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
    }).compileToV0Message()
  );

  const simulation = await connection.simulateTransaction(testVersionedTxn, {
    replaceRecentBlockhash: true,
    sigVerify: false,
  });

  if (simulation.value.err) {
    logger.error('Simulation failed with error:', JSON.stringify(simulation.value.err));
    return undefined;
  }

  return simulation.value.unitsConsumed;
}

async function startSwap() {
  let useQuickNode = true;
  while (true) {
    try {
      const mintAddress = '43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz'; // Hardcoded mint address
      const quote = await getQuote('So11111111111111111111111111111111111111112', mintAddress, SOL_AMOUNT, SLIPPAGE_BPS);
      if (!quote) {
        logger.error('Failed to fetch quote. Aborting swap.');
        continue;
      }
      const privateKeyArray = JSON.parse(WALLET_PRIVATE_KEY);
      const payer = Keypair.fromSecretKey(Uint8Array.from(privateKeyArray));
      const connection = new Connection(useQuickNode ? QUICKNODE_ENDPOINT : ALCHEMY_RPC_ENDPOINT, 'confirmed');
      logger.info(`Swapping ${SOL_AMOUNT / 1e9} SOL for token ${mintAddress}`);
      
      const selectedPriorityFee = DEFAULT_PRIORITY_FEE;
      logger.info(`Selected priority fee: ${selectedPriorityFee}`);
      
      // Fetch the instructions to include in the simulation
      const instructions = [
        // Add your necessary instructions here
      ];
      const unitsConsumed = await getSimulationUnits(connection, instructions, payer.publicKey);
      logger.info(`Units consumed in the simulation: ${unitsConsumed}`);
      if (unitsConsumed) {
        const computeUnitLimit = Math.ceil(unitsConsumed * 1.05); // Adding a margin of error
        logger.info(`Setting compute unit limit to: ${computeUnitLimit}`);
        const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice({
          microLamports: selectedPriorityFee,
        });
        
        const computeUnitLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({
          units: computeUnitLimit,
        });
        instructions.push(priorityFeeInstruction);
        instructions.push(computeUnitLimitInstruction);
        const transaction = new Transaction().add(...instructions);
        transaction.feePayer = payer.publicKey;
        transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
        transaction.sign(payer);
        const txid = await executeSwap(quote, payer, connection, selectedPriorityFee, computeUnitLimit);
        if (txid) {
          logger.info('Swap successful:', txid);
          break;
        } else {
          logger.error('Swap failed.');
        }
      } else {
        logger.error('Failed to simulate transaction. Aborting swap.');
      }
    } catch (error) {
      logger.error('An unexpected error occurred:', error);
    }
    useQuickNode = !useQuickNode; // Alternate between QuickNode and Alchemy
  }
}

startSwap();

the code does have a success rate but 2 out of three times it fails . I want to have near to 100 percent success rate even if it means increasing the priority fee

I get the following error

2024-07-28T19:47:41.058Z [info]: Fetching quote from: https://quote-api.jup.ag/v6/quote?inputMint=43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz&outputMint=So11111111111111111111111111111111111111112&amount=300000000&slippageBps=1000&swapMode=ExactOut
2024-07-28T19:47:42.036Z [info]: Quote fetched successfully:
2024-07-28T19:47:42.039Z [info]: Swapping token 43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz for 0.3 SOL
2024-07-28T19:47:42.039Z [info]: Selected priority fee: 500000
2024-07-28T19:47:43.099Z [info]: Units consumed in the simulation: 150
2024-07-28T19:47:43.099Z [info]: Setting compute unit limit to: 158
2024-07-28T19:47:43.301Z [info]: Preparing to execute swap...
2024-07-28T19:47:44.160Z [info]: Swap API response:
2024-07-28T19:47:44.631Z [info]: Simulation result:
2024-07-28T19:47:44.631Z [info]: Transaction simulation logs:
2024-07-28T19:47:44.631Z [info]: Units consumed by the transaction: 108149
2024-07-28T19:47:44.631Z [info]: Sending transaction...
2024-07-28T19:48:15.124Z [error]: Attempt 1 failed: Transaction was not confirmed in 30.00 seconds. It is unknown if it succeeded or failed. Check signature 2hP6XxMeuhY5w3Vw4MPjt3h76mgJ3rdNQByoPKSeX9pijJg3wAKBWd9ig5VxLKP1BXVR11i69viurrLjApPHpmxD using the Solana Explorer or CLI tools.
2024-07-28T19:48:15.128Z [error]: Swap execution failed:
2024-07-28T19:48:15.128Z [error]: Swap failed.


please help me figure out what is wrong 

Select parent node from a javascript object

From a list like this

table:any[] = [
    {
      name: 'A1 - John Doe', 
      icon: 'user-name',
      bold: true,
      code: 'NY',
      open: false,
      items: [
        {
          name: 'D3_AIR_ASBJHABSJAS',
          icon: 'package',
          open: false,
          items: [
            { 
              name: 'Charge Type 1',
              open: false,
              items: [
                { 
                  name: 'Charge Type 1.1',
                  icon: 'departure-nofill',
                  date: '12/10/2024'
                },
                { name: 'Charge Type 1.2'},
                { name: 'Charge Type 1.3'},
                { name: 'Charge Type 1.4',
                  items: [
                    { name: 'Charge Type 2.1'},
                    { name: 'Charge Type 2.2'},
                    { name: 'Charge Type 2.3'},
                  ]
                },
              ]
            },
            { 
              name: 'Charge Type 2',
              open: false,
              items: [
                { name: 'Charge Type 2.1'},
                { name: 'Charge Type 2.2'},
                { name: 'Charge Type 2.3',
                  items: [
                    { name: 'Charge Type 2.1.1'},
                  ]
                },
              ]
            },
            { 
              name: 'Charge Type 3',
              items: [
                { name: 'Charge Type 3.1'},
              ]
            },
          ]
        },
        {
          name: 'Hotel Beach Park',
          icon: 'departure-nofill',
          date: '12/10/2024'
        }

      ]
    },
    {name: '567', code: 'NYF',
      items: [
        { name: 'Charge Type 3.1'},
      ]
    },
  ];

how to select it’s parent node by this child value { name: 'Charge Type 1.2'},

tried hasChildNodes(). But not working.

var item={ name: 'Charge Type 1.2'};
var parent=getParentElement(item)

I want to return like

{ 
              name: 'Charge Type 1',
              open: false,
              items: [
                { 
                  name: 'Charge Type 1.1',
                  icon: 'departure-nofill',
                  date: '12/10/2024'
                },
                { name: 'Charge Type 1.2'},
                { name: 'Charge Type 1.3'},
                { name: 'Charge Type 1.4',
                  items: [
                    { name: 'Charge Type 2.1'},
                    { name: 'Charge Type 2.2'},
                    { name: 'Charge Type 2.3'},
                  ]
                },
              ]
            }

NestJS doesn’t natively support streaming file uploads

Here are two JavaScript scripts: one for the server and one for the client. These scripts facilitate file uploads using streams rather than converting the file into form data. However, since NestJS doesn’t natively support this type of file uploading, how can this be achieved within a NestJS application? What are the other option that I can consider?

server.js

import { createWriteStream } from "node:fs";

import http from "node:http";

function respond(res, code, message) {
  res.writeHead(code, {
    "Content-Type": "text/plain",

    "Content-Length": message.length,
  });

  res.end(message);
}

const server = http.createServer(async (req, res) => {
  if (req.method === "POST") {
    const filename = req.headers["content-disposition"].match(/"(.*)"/)[1];

    const file = createWriteStream(`Received-${filename}`);

    req.pipe(file);

    req.on("end", () => {
      respond(res, 200, "Thanks");
    });
  } else {
    respond(res, 200, "Hi");
  }
});

server.on("error", (err) => {
  console.log(err.stack);
});

server.on("clientError", (err, socket) => {
  if (err.code === "ECONNRESET" || !socket.writable) {
    return;
  }

  socket.end("HTTP/1.1 400 Bad Requestrnrn");
});

server.on("listening", () => {
  console.log("Server started on http://localhost:8080");
});

server.listen(8080);

client.js

import { createReadStream } from "node:fs";

async function upload(filename) {
  const res = await fetch("http://localhost:8080", {
    method: "POST",

    headers: {
      "Content-Disposition": `attachment; filename="${filename}"`,
    },

    duplex: "half",

    body: createReadStream(filename),
  });

  return res.ok;
}

console.log(await upload("TestVideo.mp4"));

Anonymous Function and Arrow Function [duplicate]

In most instances arrow functions work just fine but during one of my coding time I noticed it didn’t work as intended until I switched to anonymus function also a function This is about the second time I noticed this during my learing journey and I’ve not been able to get an accurate explanation why it is so.

const checkbox = document.querySelector('input');

checkbox.addEventListener('change', () => {

    console.log(this.checked);
    
});

const checkbox = document.querySelector('input');

checkbox.addEventListener('change', function() {

    console.log(this.checked);
    
});

In both instances I’m trying to get the boolean value when the box is checked or unchecked but the arrow function returns undefined, while the anonymus function seems to work just fine.

Highcharts Heatmap on data change is not rendering data correctly. Only rendering last category on yAxis

I am writing vue code to render a heatmap. The yAxis can be changed based on calendar selections. It renders correctly on load. But if I change the dates on my calendar, only the last category on the yAxis is being rendered.

When I look at the this.chart, it has all the data but just not rendering all the data.

My code:

components/BaseElements.vue

<template>
  <div id="filters" class="m-2">
    <DateRangePicker
      ref="picker"
      v-model="dateRange"
      opens="inline"
      show-dropdowns="true"
      auto-apply="true"
      single-date-picker="range"
      :date-range="dateRange"
      :ranges="customRanges"
      @select="handleDateRangeChange"
    >
    </DateRangePicker>

  </div>
</template>

<script>
import "bootstrap/dist/css/bootstrap.min.css";
import DateRangePicker from "vue3-daterange-picker";
import moment from "moment";
import Multiselect from "vue-multiselect";
import axios from "axios";
export default {
  components: { DateRangePicker, Multiselect },
  props: {
    startDate: {
      type: String,
      required: true,
    },
    endDate: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      dateRange: {
        startDate: this.startDate,
        endDate: this.endDate,
      },
    };
  },
  mounted() {
    this.loadData(this.dateRange.startDate, this.dateRange.endDate);
  },
  methods: {
    handleDateRangeChange(value) {
      this.dateRange.startDate = value.startDate;
      this.dateRange.endDate = value.endDate;

      this.$emit("date-range-changed", {
        startDate: this.dateRange.startDate,
        endDate: this.dateRange.endDate,
        divSelected: this.selectedDivisions,
        serviceSelected: this.selectedServices,
      });
    },

    loadData(startDate, endDate) {
      const baseURL ="http://localhost:3001/api";
      if (!baseURL) {
        console.error("VUE_APP_API_BASE_URL is not defined");
        return;
      }
      const url = `${baseURL}/filters?startDate=${moment(startDate).format(
        "YYYY-MM-DD"
      )}&endDate=${moment(endDate).format("YYYY-MM-DD")}`;


    },
 
  },
};
</script>

<style>

/* Add your component-specific styles here */
</style>

components/MainTab.vue

<template>
  <div id="webs" class="m-2 d-inline-flex">
<BaseElements
        :start-date="startDate"
        :end-date="endDate"
        @date-range-changed="updateDateRange"
      />
    <div style="width: 100%" class="d-flex flex-column">
      <HeatMap id="heatMap" style="width: 100%" />
    </div>
  </div>
</template>

<script>
import "bootstrap/dist/css/bootstrap.min.css";
import HeatMap from "./WebTab/HeatMap.vue";

export default {
  components: { HeatMap },
};
</script>

<style>
/* Add your component-specific styles here */
</style>

components/MainHeatMap.vue

<template>
  <div>
    <highcharts
      :constructor-type="'chart'"
      class="hc"
      :options="chartOptions"
      ref="chart"
    ></highcharts>
  </div>
</template>

<script>
import moment from "moment";

export default {
  props: {
    chartData: {
      type: Array,
      default: () => [],
    },
    divisionProp: {
      type: String,
      default: "division",
    },
    serviceProp: {
      type: String,
      default: "service",
    },
    profileNameProp: {
      type: String,
      default: "profile_name",
    },
    reportDateProp: {
      type: String,
      default: "report_date",
    },
    videoViewsProp: {
      type: String,
      default: "insight_video_views",
    },
  },
  data() {
    const vm = this;
    return {
      chartOptions: {
        chart: {
          backgroundColor: "#fbfcf8",
          type: "heatmap",
          plotBorderWidth: 1,
          height: "100%",
          events: {
            redraw: function () {
              if (!vm.initialLoad) {
                console.log(this.series[0].data);
                console.log(vm.seriesData);
              }
            },
            drilldown: function (e) {
              if (e.seriesOptions !== undefined) {
                const drilldowns = [
                  ...new Set(e.seriesOptions.data.map((d) => d.name)),
                ];
                this.xAxis[0].categories = drilldowns;
              }
            },
            drillup: function (e) {
              const drillups = [
                ...new Set(e.seriesOptions.data.map((d) => d.name)),
              ];
              this.xAxis[0].categories = drillups;
            },
          },
        },
        title: {
          text: "Views",
          align: "center",
        },
        exporting: {
          enabled: true,
          buttons: {
            contextButton: {
              menuItems: [
                "viewFullscreen",
                "printChart",
                "separator",
                "downloadPNG",
                "downloadJPEG",
                "separator",
                "downloadPDF",
                "downloadCSV",
              ],
            },
          },
        },
        credits: {
          enabled: false,
        },
        legend: {
          enabled: true,
          itemStyle: {
            color: "#000",
          },
        },
        rangeSelector: {
          enabled: false,
        },
        navigator: {
          enabled: false,
        },
        scrollbar: {
          enabled: false,
        },
        xAxis: {
          categories: [],
        },
        yAxis: {
          title: "",
          categories: [],
          reversed: false,
        },
        accessibility: {
          point: {
            descriptionFormat:
              "{(add index 1)}. " +
              "{series.xAxis.categories.(x)} " +
              "{series.yAxis.categories.(y)}, {value}.",
          },
        },
        colorAxis: {
          min: 0,
          minColor: "#FFFFFF",
          maxColor: "#DA70D6",
        },
        tooltip: {
          style: { color: "#000" },
          formatter() {
            const addCommas = (value) => {
              return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
            };
            return (
              `<b>${this.series.xAxis.categories[this.point.x]}</b> had<br>` +
              `<b>${addCommas(
                this.point.value
              )}</b> video views in the week of <br>` +
              `<b>${this.series.yAxis.categories[this.point.y]}</b>`
            );
          },
        },
        series: [
          {
            name: "Video Views",
            borderWidth: 1,
            data: [],
            dataLabels: {
              enabled: true,
              color: "#000000",
              formatter() {
                const numericSymbols = ["K", "M", "G", "T", "P", "E"];
                if (this.point.value >= 1000) {
                  const symbolIndex = Math.floor(
                    Math.log10(this.point.value) / 3
                  );
                  const scaledValue =
                    this.point.value / Math.pow(1000, symbolIndex);
                  const symbol = numericSymbols[symbolIndex - 1];
                  return `${Math.ceil(scaledValue)}${symbol}`;
                }
                return this.point.value;
              },
            },
          },
        ],
        drilldown: {
          series: [],
        },
        responsive: {
          rules: [
            {
              condition: {
                maxWidth: 500,
              },
              chartOptions: {
                yAxis: {
                  labels: {
                    format: "{substr value 0 1}",
                  },
                },
              },
            },
          ],
        },
      },
      fullData: [],
      seriesData: [],
      initialLoad: true,
    };
  },
  watch: {
    chartData: {
      handler(newChartData, oldChartData) {
        if (newChartData !== oldChartData) {
          this.updateChartData(newChartData);
        }
      },
      deep: true,
    },
  },
  created() {
    this.updateChartData(this.chartData);
  },
  methods: {
    updateChartData(data) {
      this.fullData = data;
      const filteredData = this.fullData.map((item) => ({
        division: item[this.divisionProp],
        service: item[this.serviceProp],
        profile_name: item[this.profileNameProp],
        report_date: item[this.reportDateProp],
        insight_video_views: item[this.videoViewsProp],
      }));

      const generateDateRanges = (fullData, groupBy) => {
        const dates = [...new Set(fullData.map((dt) => dt.report_date))].sort();
        const startDate = moment(dates[0]);
        const endDate = moment(dates[dates.length - 1]);

        const diffDays = endDate.diff(startDate, "days");
        const diffMonths = endDate.diff(startDate, "months");

        const sumInsightVideoViews = (start, end, groupValue) =>
          fullData
            .filter(
              (dt) =>
                dt[groupBy] === groupValue &&
                moment(dt.report_date).isBetween(start, end, null, "[)")
            )
            .reduce((sum, dt) => sum + dt.insight_video_views, 0);

        const uniqueGroupValues = [
          ...new Set(fullData.map((dt) => dt[groupBy])),
        ];
        const ranges = [];

        uniqueGroupValues.forEach((groupValue) => {
          let current = startDate.clone();

          while (current.isBefore(endDate) || current.isSame(endDate, "day")) {
            let next;
            let format;

            if (diffDays <= 14) {
              current.startOf("day");
              next = current.clone().add(1, "day");
              format = "ll";
            } else if (diffMonths <= 6) {
              current.startOf("week");
              next = current.clone().add(1, "week");
              format = "ll";
            } else {
              current.startOf("month");
              next = current.clone().add(1, "month");
              format = "MMMM, YYYY";
            }

            const division = fullData.find(
              (dt) => dt[groupBy] === groupValue
            ).division;

            ranges.push({
              [groupBy]: groupValue,
              division: division,
              date: current.format(format),
              insight_video_views: sumInsightVideoViews(
                current,
                next,
                groupValue
              ),
            });

            current = next;
          }
        });

        return ranges;
      };

      let yAxis = [
        ...new Set(
          generateDateRanges(filteredData, "division").map((d) => d.date)
        ),
      ];

      let xAxis = [
        ...new Set(
          generateDateRanges(filteredData, "division").map((d) => d.division)
        ),
      ];

      this.chartOptions.yAxis.categories = yAxis;
      this.chartOptions.xAxis.categories = xAxis;

      const groupBy = (array, property) => {
        return array.reduce((acc, item) => {
          const key = item[property];
          if (!acc[key]) {
            acc[key] = [];
          }
          acc[key].push(item);
          return acc;
        }, {});
      };
      // Group by division
      const groupedByDivision = groupBy(
        generateDateRanges(filteredData, "division"),
        "division"
      );

      // Group by service
      const groupedByService = groupBy(
        generateDateRanges(filteredData, "service"),
        "service"
      );

      const seriesData = Object.keys(groupedByDivision).flatMap((division) => {
        const divisionIndex = xAxis.indexOf(division);
        return groupedByDivision[division].map((range, dateIndex) => ({
          x: divisionIndex,
          y: dateIndex,
          value: range.insight_video_views,
          name: division,
          id: division,
          drilldown: division,
        }));
      });
      this.seriesData = seriesData;
      this.chartOptions.series[0].data = this.seriesData;

      const transformDrill = (data) => {
        const result = {};
        const serviceIndexMap = {};

        for (const [service, items] of Object.entries(data)) {
          for (let index = 0; index < items.length; index++) {
            const { division, insight_video_views } = items[index];
            if (!result[division]) result[division] = [];
            if (!serviceIndexMap[division]) serviceIndexMap[division] = {};
            if (serviceIndexMap[division][service] === undefined) {
              serviceIndexMap[division][service] = Object.keys(
                serviceIndexMap[division]
              ).length;
            }
            const x = serviceIndexMap[division][service];
            result[division].push({
              x,
              y: index,
              value: insight_video_views,
              name: service,
            });
          }
        }

        return Object.entries(result).map(([id, data]) => ({
          id,
          borderWidth: 1,
          dataLabels: {
            enabled: true,
            color: "#000000",
            formatter() {
              const numericSymbols = ["K", "M", "G", "T", "P", "E"];
              if (this.point.value >= 1000) {
                const symbolIndex = Math.floor(
                  Math.log10(this.point.value) / 3
                );
                const scaledValue =
                  this.point.value / Math.pow(1000, symbolIndex);
                const symbol = numericSymbols[symbolIndex - 1];
                return `${Math.ceil(scaledValue)}${symbol}`;
              }
              return this.point.value;
            },
          },
          data,
        }));
      };
      const drilldownData = transformDrill(groupedByService);
      this.chartOptions.drilldown.series = drilldownData;
      console.log(this.chartOptions);
      console.log(this.initialLoad);
      this.initialLoad = false;
    },
  },
};
</script>
<style>
.highcharts-heatmap-series > .highcharts-drilldown-point {
  cursor: default !important;
}

.highcharts-heatmap-series > .highcharts-drilldown-data-label {
  cursor: default !important;
}

.highcharts-heatmap-series > .highcharts-drilldown-data-label > text {
  text-decoration: none !important;
  color: #000000 !important;
  fill: #000000 !important;
}
</style>

On load, it loads correctly:
enter image description here

But on date change:
enter image description here

The problem is that console.log(this.chartOptions); returns the updated yAxis and updated this.chartOptions.series[0].data. So not sure why it is not rendering correctly. this.series[0].setData(vm.seriesData); is just not loading any chart on the page.

SQL Query Executor using Django

I am a beginner in software development, I am task to develop a web-based application, in which I use Django Web Framework, that can Execute SQL queries against a MS SQL Server Database, display the results of the query and log the details into the Django database (PostgreSQL), like timestamp, user, SQL Statement, errors, results etc, it is working. But, can you guys give me how to improve this? In my template, I use Ajax, and planning to use reactJS as frontend, but I am not really into it right now due to I need to learn it first.

Objective:

(1). I want to store the results in the session, retrieve it using ajax from the session and display the results.

(2). but I want to add a unique ID using the generate_session_id() to that session data to identify that particular session data and retrieve it using ajax and display it the session data.

(3). and to also enable the user to open new tab and run another SQL query executor.

(3.1). Every time the page is reloaded or the page is ready, or the user open it in another tab, the unique session id should be different or renew the unique ID using the cleanup_old_sessions(). For now, the cleanup_old_sessions() is set to be cleaned up if the session data is 1 hour old.

(3.2). But, I want the session ID to be renewed every time.

Thank you, your reply will greatly help me and will very much appreciated.

Note: I code I have here is from research with ChatGPT 🙂

views.py:

def generate_session_id():
"""Generate a random session ID."""
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=16))


@login_required(login_url='/admin/login')
def execute_sql(request):

title = 'SQL Query Executor'

# Check if session_id already exists in the session
session_id = request.session.get('current_session_id')
if not session_id:
    # Generate a unique session ID for the request
    session_id = generate_session_id()
    request.session['current_session_id'] = session_id
    request.session['current_timestamp'] = time.time()

# Cleanup old session data
cleanup_old_sessions(request)

result = None
error = None
columns = []
sql_log_id = None
row_count = 0
processing_time = None
sql_log_processing_time = None
processing_time_str = None

if request.method == 'POST':
    start_time = time.time()  # Record the start time
    form = SQLForm(request.POST, user=request.user)
    if form.is_valid():

        sql = form.cleaned_data['sql_statement'].strip().lower()
        connection = form.cleaned_data['connection']
        save_query = form.cleaned_data['save_query']
        
        # Update the database connection based on the database connection selected
        settings.DATABASES['remote'].update({
            'NAME': connection.database,
            'USER': connection.username,
            'PASSWORD': connection.password,
            'HOST': connection.host,
            'PORT': connection.port,
        })
        
        if any(sql.strip().lower().startswith(prefix) for prefix in ALLOWED_SQL_PREFIXES):
            try:
                with connections['remote'].cursor() as cursor:
                    cursor.execute(sql)
                    columns = [col[0] for col in cursor.description]
                    rows = cursor.fetchall()
                    result = rows
                    row_count = len(rows)

                    cols_rows = {'columns': columns, 'rows': result}
                    serializable_cols_rows = convert_to_serializable(cols_rows)

                    # # Convert result to be JSON serializable
                    serializable_result = convert_to_serializable(rows)

                    # # Save the result in session for downloading
                    request.session[f'result_{session_id}'] = serializable_result
                    request.session[f'columns_{session_id}'] = convert_to_serializable(columns)
                    request.session[f'row_count_{session_id}'] = row_count
                    request.session[f'user_{session_id}'] = convert_to_serializable(str(request.user))

                    # Collect user's groups
                    user_groups = request.user.groups.all()
                    user_groups_str = ', '.join(group.name for group in user_groups)
                    
                    # Calculate the processing time
                    processing_time_raw = time.time() - start_time
                    
                    # Convert the duration to a timedelta object
                    processing_time = timedelta(seconds=processing_time_raw)

                    # Convert the duration to milliseconds
                    milliseconds = processing_time_raw * 1000

                    # Compute hours, minutes, seconds, and milliseconds
                    hours, milliseconds     = divmod(milliseconds, 3600000)
                    minutes, milliseconds   = divmod(milliseconds, 60000)
                    seconds, milliseconds   = divmod(milliseconds, 1000)
                    
                    # Format the duration string
                    processing_time_str = f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}:{int(milliseconds):03}"

                    # Save the SQL log
                    sql_log = SQLLog.objects.create(
                        user=request.user,
                        user_groups=user_groups_str,
                        connection=connection,
                        sql_statement=sql,
                        result=json.dumps(serializable_cols_rows),
                        row_count=row_count,
                        remarks='query',
                        processing_time=processing_time
                    )

                    # Save the query to a separate model if the checkbox is checked
                    if save_query:
                        SavedQuery.objects.create(
                            user=request.user,
                            sql_statement=sql
                        )
                   
                    # Get SQLLog id
                    sql_log_id = sql_log.id
                    sql_log_timestamp = sql_log.timestamp
                    sql_log_processing_time = sql_log.processing_time

                    # Save SQLLog id in session
                    request.session[f'sql_log_id_{session_id}'] = convert_to_serializable(sql_log_id)
                    request.session[f'timestamp_{session_id}'] = convert_to_serializable(sql_log_timestamp)
                    request.session[f'processing_time_{session_id}'] = sql_log_processing_time.total_seconds()

            except Exception as e:
                error = str(e)
                request.session[f'error_{session_id}'] = error
                logger.error("SQL Execution Error: %s", error)
                
                # Collect user's groups
                user_groups = request.user.groups.all()
                user_groups_str = ', '.join(group.name for group in user_groups)
                
                # Calculate the processing time
                processing_time_raw = time.time() - start_time
                
                # Convert the duration to a timedelta object
                processing_time = timedelta(seconds=processing_time_raw)

                # Convert the duration to milliseconds
                milliseconds = processing_time_raw * 1000

                # Compute hours, minutes, seconds, and milliseconds
                hours, milliseconds     = divmod(milliseconds, 3600000)
                minutes, milliseconds   = divmod(milliseconds, 60000)
                seconds, milliseconds   = divmod(milliseconds, 1000)
                
                # Format the duration string
                processing_time_str = f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}:{int(milliseconds):03}"

                # Save the SQL log
                sql_log = SQLLog.objects.create(
                    user=request.user,
                    user_groups=user_groups_str,
                    connection=connection,
                    sql_statement=sql,
                    error=error,
                    remarks='query',
                    processing_time=processing_time
                )

                # Save the query to a separate model if the checkbox is checked
                if save_query:
                    SavedQuery.objects.create(
                        user=request.user,
                        sql_statement=sql
                    )
                
                # Get SQLLog id
                sql_log_id = sql_log.id
                sql_log_timestamp = sql_log.timestamp
                sql_log_processing_time = sql_log.processing_time

                # Save SQLLog id in session
                request.session[f'sql_log_id_{session_id}'] = convert_to_serializable(sql_log_id)
                request.session[f'timestamp_{session_id}'] = convert_to_serializable(sql_log_timestamp)
                request.session[f'processing_time_{session_id}'] = sql_log_processing_time.total_seconds()
        else:
            error = "Only SELECT statements are allowed."
            request.session[f'error_{session_id}'] = error
            logger.warning("Invalid SQL Statement: %s", sql)

            # Collect user's groups
            user_groups = request.user.groups.all()
            user_groups_str = ', '.join(group.name for group in user_groups)
            
            # Calculate the processing time
            processing_time_raw = time.time() - start_time
            
            # Convert the duration to a timedelta object
            processing_time = timedelta(seconds=processing_time_raw)

            # Convert the duration to milliseconds
            milliseconds = processing_time_raw * 1000

            # Compute hours, minutes, seconds, and milliseconds
            hours, milliseconds     = divmod(milliseconds, 3600000)
            minutes, milliseconds   = divmod(milliseconds, 60000)
            seconds, milliseconds   = divmod(milliseconds, 1000)
            
            # Format the duration string
            processing_time_str = f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}:{int(milliseconds):03}"

            # Save the SQL log
            sql_log = SQLLog.objects.create(
                user=request.user,
                user_groups=user_groups_str,
                connection=connection,
                sql_statement=sql,
                error=error,
                remarks='query',
                processing_time=processing_time
            )

            # Save the query to a separate model if the checkbox is checked
            if save_query:
                SavedQuery.objects.create(
                    user=request.user,
                    sql_statement=sql
                )
            
            # Get SQLLog id
            sql_log_id = sql_log.id
            sql_log_timestamp = sql_log.timestamp
            sql_log_processing_time = sql_log.processing_time

            # Save SQLLog id in session
            request.session[f'sql_log_id_{session_id}'] = convert_to_serializable(sql_log_id)
            request.session[f'timestamp_{session_id}'] = convert_to_serializable(sql_log_timestamp)
            request.session[f'processing_time_{session_id}'] = sql_log_processing_time.total_seconds()
        
        # Return JSON response for AJAX request
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            if error:
                return JsonResponse({'status': 'error', 'error': error}, status=400)
            else:
                return JsonResponse({
                    'status': 'completed',
                    'result': result,
                    'columns': columns,
                    'row_count': row_count,
                    'sql_log_id': sql_log_id,
                    'processing_time': processing_time_str
                })

else:

    form = SQLForm(user=request.user)

return render(request, 'sql_executor/sql_exec.html', {
    'form': form, 
    'result': result, 
    'columns': columns,
    'row_count': row_count,
    'error': error,
    'sql_log_id': sql_log_id,
    'title': title,
    'processing_time': processing_time_str,
    'session_id': session_id
})

def cleanup_old_sessions(request, max_age=3600):
"""Clean up old session data older than max_age seconds."""
current_time = time.time()
for key in list(request.session.keys()):
    if key.startswith('result_') or key.startswith('columns_') or key.startswith('row_count_') or key.startswith('error_') or key.startswith('processing_time_'):
        session_id = key.split('_')[-1]
        timestamp_key = f'current_timestamp_{session_id}'
        timestamp = request.session.get(timestamp_key)
        print(current_time)
        print(timestamp)
        if timestamp and (current_time - timestamp > max_age):
            # Delete session data if it is older than max_age
            del request.session[key]
            del request.session[timestamp_key]

@login_required(login_url='/admin/login')
def check_status(request):

session_id = request.GET.get('session_id')  # Get the session ID from the request

if not session_id:
    return JsonResponse({'error': 'Session ID is required.'}, status=400)

print(f"Session_ID Check status: {session_id}")
result = request.session.get(f'result_{session_id}')
columns = request.session.get(f'columns_{session_id}')
row_count = request.session.get(f'row_count_{session_id}')
error = request.session.get(f'error_{session_id}')
sql_log_id = request.session.get(f'sql_log_id_{session_id}')
processing_time_raw = request.session.get(f'processing_time_{session_id}')

# Handle the case where processing_time_raw is None
if processing_time_raw is None:
    processing_time_str = "00:00:00:000"
else:
    # Convert the duration to milliseconds
    milliseconds = processing_time_raw * 1000

    # Compute hours, minutes, seconds, and milliseconds
    hours, milliseconds     = divmod(milliseconds, 3600000)
    minutes, milliseconds   = divmod(milliseconds, 60000)
    seconds, milliseconds   = divmod(milliseconds, 1000)
    
    # Format the duration string
    processing_time_str = f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}:{int(milliseconds):03}"

# Limit the number of rows sent back
page = int(request.GET.get('page', 1))
page_size = 50
start = (page - 1) * page_size
end = start + page_size
paginated_result = result[start:end] if result else []

if result is not None:
    status = 'completed'
elif error is not None:
    status = 'error'
else:
    status = 'processing'

return JsonResponse({
    'status': status,
    'result': paginated_result,
    'columns': columns,
    'row_count': row_count,
    'error': error,
    'page': page,
    'has_more': end < row_count if row_count is not None else False,
    'sql_log_id': sql_log_id,
    'processing_time': processing_time_str
})

template:
{% extends "./includes/base.html" %}
{% load static %}
{% block content %}

<style>
    .scrollable-div {
        max-height: 700px; /* Adjust this value as needed */
        overflow-y: auto;
    }

    .form-check-input {
        margin-left: 50px;
    }
</style>

<h1 class="mb-4">Execute SQL Query</h1>
        <p style="color: red;"><em><strong>Note:</strong> Due to the limitations of this web-based application, extracting large amounts of data may sometimes fail. If this occurs, please adjust your query, especially if it includes a date range. For example, try narrowing the date range or reducing the amount of data requested. If you continue to experience issues, ensure you are using a compatible browser and device, or contact technical support for further assistance. Thank you.</em></p>
        <form method="post" id="sql-form">
            {% csrf_token %}
            <input type="hidden" name="session_id" value="{{ session_id }}">
            <div class="form-group">
                {{ form.as_p }}
            </div>
            <button id="sql-submit" type="submit" class="btn btn-primary">Execute SQL Query</button>
            <button id="sql-reset" type="button" class="btn btn-primary">Reset</button>
        </form>

        <div id="message-error" class="mt-4 alert alert-danger" style="display: none;"></div>

        <div id="message" class="mt-4 alert alert-info" style="display: none;">
            <div class="spinner-border" role="status">
                <span class="sr-only">Loading...</span>
            </div>
            <span id="message-text"></span>
        </div>
        {% if error %}
        <hr />
            <div id="error-section" style="display:block;">
                <h2>Error:</h2>
                <pre id="error-message">{{ error }}</pre>
            </div>
        {% else %}
        <hr />
            <div id="error-section" style="display:none;">
                <h2>Error:</h2>
                <pre id="error-message"></pre>
            </div>
        {% endif %}
        <div id="result-section" class="mt-4" style="display: none;">
            <h2>Results:</h2>
            <hr />
            <p>Number of rows: <span id="row-count"></span></p>
            <p>Processing time: <span id="processing-time"></span></p>
            <hr />
            <a id="download-result" href="#" class="btn btn-success btn-sm">Download results</a>
            <a id="view-result" href="#" target="_blank" class="btn btn-success btn-sm">View details</a>
            <p><code>ONLY 50 rows are displayed</code></p>
            <div class="scrollable-div">
                <table class="table table-striped">
                    <thead>
                        <tr id="table-header">
                            <th>#</th> <!-- Add '#' header -->
                        </tr>
                    </thead>
                    <tbody id="table-body"></tbody>
                </table>
            </div>
        </div>

        
    </div>

{% endblock %}

JavaScript:
<script>
        $(document).ready(function() {

            var statusInterval;

            $('#sql-form').on('submit', function(event) {

                event.preventDefault();

                var statusInterval = setInterval(checkStatus, 5000);

                $('#sql-submit').prop('disabled', true);
                $('#message').show();
                $('#message-text').text('Executing SQL query, please wait...');

                // Clear previous results
                $('#result-section').hide();
                $('#error-section').hide();
                $('#table-header').html('<th>#</th>'); // Add '#' header
                $('#table-body').empty();

                // Submit the form via AJAX
                var formData = new FormData(this);
                $.ajax({
                    url: '{% url "sql_executor:execute_sql" %}',
                    type: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function(data) {
                        if (data.status === 'error') {
                            displayError(data.error);
                        } else{
                            checkStatus();
                        }
                    },
                    error: function(xhr) {
                        var errorData;
                        try {
                            errorData = xhr.responseJSON;
                        } catch (e) {
                            errorData = null;
                        }
                        var errorMessage = errorData && errorData.error ? errorData.error : 'Error executing SQL query.';
                        displayError(errorMessage);
                    },
                    complete: function() {
                        clearInterval(statusInterval);
                    }
                });
            });
        
            function checkStatus() {
                $.ajax({
                    url: '/tools/check-status/?session_id={{session_id}}',
                    type: 'GET',
                    success: function(data) {
                        if (data.status === 'completed') {
                            clearInterval(statusInterval);
                            displayResult(data);
                        } else if (data.status === 'error') {
                            clearInterval(statusInterval);
                            displayError(data.error);
                        } else {
                            // Update UI to indicate ongoing execution
                            $('#message-text').text('Query execution in progress...');
                        }
                    },
                    error: function() {
                        console.error('Error checking status.');
                    },
                    complete: function() {
                        clearInterval(statusInterval);
                    }
                });
            }

            function displayResult(data) {
                $('#sql-submit').prop('disabled', false);
                $('#message').hide();

                var columns = data.columns;
                var rows = data.result;
                var rowCount = data.row_count;
                var processingTime = data.processing_time;
                var sqlLogId = data.sql_log_id;
                
                $('#row-count').text(rowCount);
                $('#processing-time').text(processingTime);

                var headerRow = $('#table-header');
                columns.forEach(function(col) {
                    var th = $('<th></th>').text(col);
                    headerRow.append(th);
                });

                var tableBody = $('#table-body');
                rows.forEach(function(row, index) {
                    var tr = $('<tr></tr>');
                    var tdIndex = $('<td></td>').text(index + 1);
                    tr.append(tdIndex);

                    row.forEach(function(cell) {
                        var td = $('<td></td>').text(cell);
                        tr.append(td);
                    });

                    tableBody.append(tr);
                });

                // Update the download link with the sql_log_id
                $('#download-result').attr('href', '/tools/sqllog-details/' + sqlLogId + '/?download_excel=true');
                $('#view-result').attr('href', '/tools/sqllog-details/' + sqlLogId + '/');

                $('#result-section').show();
            }

            function displayError(error) {
                $('#sql-submit').prop('disabled', false);
                $('#message').hide();
                $('#error-message').text(error);
                $('#error-section').show();
            }

            $('#sql-reset').on('click', function() {
                location.reload();
            });

            
        
        });
    </script>

classList.add method doesn’t work and component is rerendered when clicking file input in Svelte

I want to make the image upload box open and close. In my code, the opening function works, but for some reason, the closing function doesn’t work. Additionally, when I use console.log in the functions responsible for opening and closing, the console.log in the closing function runs twice. I also tried using another approach variable = !variable, but this approach has problem when the file input button is clicked, it causes the page to rerender, which resets the state variable to false, causing the box to close again. Does anyone know how to fix this?

<script>
    let article = {}
    
    let base64Image
    
    let articleViewer
    
    let imageUploadBox
    
    function showImageUpload(){
        if (imageUploadBox.classList.contains("hidden")){
            imageUploadBox.classList.remove("hidden")
            console.log(imageUploadBox.classList)
        }
    }
    
    function closeImageUpload(){
        if (!imageUploadBox.classList.contains("hidden")){
            imageUploadBox.classList.add("hidden")
            console.log(imageUploadBox.classList)
        }
    }
    
    function processImage(e){
        const image = e.target.files[0]
        const imageReader = new FileReader()
        imageReader.onload = (e) => {
            base64Image = e.target.result
        }
        imageReader.readAsDataURL(image)
    }
    
    function insertImage(image){
        let selection = window.getSelection()
        let range = selection.getRangeAt(0)
        
        if (articleViewer.contains(range.commonAncestorContainer)){
            let imgTag = document.createElement("img")
            imgTag.src = image
            imgTag.className = "w-[50%] m-auto rounded-lg"
            
            range.deleteContents()
            range.insertNode(imgTag)
            
            range.setStartAfter(imgTag)
            range.collapse(true)
            selection.removeAllRanges()
            selection.addRange(range)
            
            base64Image = ""
        }
        else {
            alert("Images can only be inserted in the article content")
        }
    }
    
    function updateArticle(){}
</script>

<div class="flex flex-col gap-4 p-8 h-screen">
    <input type="text" class="bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:value={article["title"]} />
    <div class="relative">
        <button on:click={() => showImageUpload()} >
            <svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" height="40px" width="40px"><path fill="white" d="M13.3 34.15h21.45q.5 0 .7-.4.2-.4-.1-.8l-5.85-7.8q-.25-.3-.6-.3t-.6.3l-6 7.75-4.05-5.55q-.25-.3-.6-.3t-.6.3l-4.3 5.6q-.25.4-.075.8t.625.4ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/></svg>
            <!--{#if imageUploadBox}-->
                <div class="hidden bg-emerald-500 p-8 rounded-lg flex justify-center items-center flex-col gap-8 absolute top-[110%] relative" bind:this={imageUploadBox}>
                    <input type="file" accept="images/*" on:change={processImage} class="rounded-lg text-emerald-100 text-xs font-semibold bg-emerald-950 p-4" />
                    {#if base64Image}
                        <img src={base64Image} class="rounded-lg w-[50%]" />
                        <button on:click={insertImage(base64Image)} class="bg-emerald-950 text-emerald-100 p-4 text-xs font-semibold rounded-lg" >Add</button>
                    {/if}
                    <button on:click={closeImageUpload} class="p-4 rounded-full absolute bottom-[100%] right-[100%] bg-emerald-950" >
                        <svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" height="1.5em" width="1.5em"><path fill="white" d="M24 26.1 13.5 36.6q-.45.45-1.05.45-.6 0-1.05-.45-.45-.45-.45-1.05 0-.6.45-1.05L21.9 24 11.4 13.5q-.45-.45-.45-1.05 0-.6.45-1.05.45-.45 1.05-.45.6 0 1.05.45L24 21.9l10.5-10.5q.45-.45 1.05-.45.6 0 1.05.45.45.45.45 1.05 0 .6-.45 1.05L26.1 24l10.5 10.5q.45.45.45 1.05 0 .6-.45 1.05-.45.45-1.05.45-.6 0-1.05-.45Z"/></svg>
                    </button>
                </div>
            <!--{/if}-->
        </button>
    </div>
    <div id="articleViewer" class="bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:innerHTML={article["content"]} contenteditable="true" bind:this={articleViewer}>hello</div>
</div>

<style>
    input:active {
        border: 0;
        outline: 0;
    }
    
    .hidden {
        display: none;
    }
</style>

The other approach that caused rerender, the rerender happens when I click the <input type="file" /> :

<script>
    let article = {}
    
    let base64Image
    
    let articleViewer
    
    let imageUploadBox = false
    
    function showImageUpload(){
        imageUploadBox = !imageUploadBox
    }
    
    function closeImageUpload(){
        imageUploadBox = !imageUploadBox
    }
    
    function processImage(e){
        const image = e.target.files[0]
        const imageReader = new FileReader()
        imageReader.onload = (e) => {
            base64Image = e.target.result
        }
        imageReader.readAsDataURL(image)
    }
    
    function insertImage(image){
        let selection = window.getSelection()
        let range = selection.getRangeAt(0)
        
        if (articleViewer.contains(range.commonAncestorContainer)){
            let imgTag = document.createElement("img")
            imgTag.src = image
            imgTag.className = "w-[50%] m-auto rounded-lg"
            
            range.deleteContents()
            range.insertNode(imgTag)
            
            range.setStartAfter(imgTag)
            range.collapse(true)
            selection.removeAllRanges()
            selection.addRange(range)
            
            base64Image = ""
        }
        else {
            alert("Images can only be inserted in the article content")
        }
    }
    
    function updateArticle(){}
</script>

<div class="flex flex-col gap-4 p-8 h-screen">
    <input type="text" class="bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:value={article["title"]} />
    <div class="relative">
        <button type="button" on:click={() => showImageUpload()} >
            <svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" height="40px" width="40px"><path fill="white" d="M13.3 34.15h21.45q.5 0 .7-.4.2-.4-.1-.8l-5.85-7.8q-.25-.3-.6-.3t-.6.3l-6 7.75-4.05-5.55q-.25-.3-.6-.3t-.6.3l-4.3 5.6q-.25.4-.075.8t.625.4ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/></svg>
            {#if imageUploadBox}
                <div class="bg-emerald-500 p-8 rounded-lg flex justify-center items-center flex-col gap-8 absolute top-[110%] relative">
                    <input type="file" accept="images/*" on:change={processImage} class="rounded-lg text-emerald-100 text-xs font-semibold bg-emerald-950 p-4" />
                    {#if base64Image}
                        <img src={base64Image} class="rounded-lg w-[50%]" />
                        <button type="button" on:click={() => insertImage(base64Image)} class="bg-emerald-950 text-emerald-100 p-4 text-xs font-semibold rounded-lg" >Add</button>
                    {/if}
                    <button type="button" on:click={closeImageUpload} class="p-4 rounded-full absolute bottom-[100%] right-[100%] bg-emerald-950" >
                        <svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" height="1.5em" width="1.5em"><path fill="white" d="M24 26.1 13.5 36.6q-.45.45-1.05.45-.6 0-1.05-.45-.45-.45-.45-1.05 0-.6.45-1.05L21.9 24 11.4 13.5q-.45-.45-.45-1.05 0-.6.45-1.05.45-.45 1.05-.45.6 0 1.05.45L24 21.9l10.5-10.5q.45-.45 1.05-.45.6 0 1.05.45.45.45.45 1.05 0 .6-.45 1.05L26.1 24l10.5 10.5q.45.45.45 1.05 0 .6-.45 1.05-.45.45-1.05.45-.6 0-1.05-.45Z"/></svg>
                    </button>
                </div>
            {/if}
        </button>
    </div>
    <div id="articleViewer" class="bg-emerald-500 text-white p-4 rounded-lg focus:border-none focus:outline-none" bind:innerHTML={article["content"]} contenteditable="true" bind:this={articleViewer}>hello</div>
</div>

<style>
    input:active {
        border: 0;
        outline: 0;
    }
    
    .hidden {
        display: none;
    }
</style>

Array of Promises running on Declaration

It appears that the promises are running as soon as declared in the array and not when promise.all is called.

    p1 = new Promise(function (resolve, reject) {
        console.log('running geek1');
        const date = Date.now();
        let currentDate = null;
        do {
            currentDate = Date.now();
        } while (currentDate - date < 2000);
        resolve('timeout geek1');
    });

    p3 = new Promise(function (resolve, reject) {
        console.log('running geek3');
        const date = Date.now();
        let currentDate = null;
        do {
            currentDate = Date.now();
        } while (currentDate - date < 2000);
        resolve('geek3');
    });
    p4 = function () {
        return new Promise(function (resolve, reject) {
            console.log('running geek4');
            resolve('geek4');
        });
    }
    p5 = new Promise(function (resolve, reject) {
        console.log('running geek5');
        resolve('geek5');
    });

When you run it notice the delay I put it pauses the execution of the javascript. Which means to me this is running the code inside the promise as soon as I declare it.

results are:

running geek1
running geek3
running geek5

notice it doesn’t run p4 cause I returned the promise so it wouldn’t execute immediately.

But if I add

Promise.all([p1, p4, p5, p3]).then(function (values) {
    console.log(values);
});

I get the following out

running geek1
running geek3
running geek5
['timeout geek1', [Function: p4], 'geek5', 'geek3']

Notice that p4 did not run under promise.all and returned the value as a function.

How do I create a dynamic array of promises to run them under Promise.all?

I find conflicting examples on technique. It doesn’t make sense why I need to do return new promise to make sure it doesn’t run on declaration. It is a constructor and I am passing in a function definition. So why is it running?

If I did the following:

    class SampleClass {
        constructor(testFunc, value) {
            this.testFunc = testFunc;
            this.value = value;
        }
        writeIt(){
            console.log(this.testFunc(this.value));
        }
    }

    console.log("declare");

    let sc = new SampleClass((value) => { console.log(value); value++; console.log(value); return "added value" }, 453);
    console.log("between");
    sc.writeIt();

it works as I expect it the values don’t get written until I call writeIt()
this is what it returns.

declare
between
453
454
added value

Help is greatly appreciated.

telegram bot, cannot figure out the problem

I been struggling to deploy my bot. Im getting an error message. Im also having trouble with Jest.
These are const on my .env file/ or variables I dont know exactly what its called. If someone can please guide me and let me know how to fix this.

const Web3 = require('web3');
const TelegramBot = require('node-telegram-bot-api');
require('dotenv').config();

// Load environment variables
const token = process.env.TELEGRAM_BOT_TOKEN;
const infuraEndpoint = process.env.INFURA_OR_ALCHEMY_ENDPOINT;
const contractAddress = process.env.CONTRACT_ADDRESS;
const privateKey = process.env.PRIVATE_KEY;
const chatId = process.env.TELEGRAM_CHAT_ID;

const bot = new TelegramBot(token, { polling: true });
const web3 = new Web3(infuraEndpoint);

// Replace with your contract's ABI
const abi = [
    {
        "inputs": [],
        "name": "get",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "uint256",
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "set",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
];
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
web3.eth.accounts.wallet.add(account);
web3.eth.defaultAccount = account.address;

const contract = new web3.eth.Contract(abi, contractAddress);

// Function to handle trade confirmation
async function handleTradeConfirmation(chatId, token, amountIn, minAmountOut) {
    const message = `Do you want to trade ${web3.utils.fromWei(amountIn, 'ether')} ETH for ${token}? Minimum tokens expected: ${web3.utils.fromWei(minAmountOut, 'ether')}`;

    // Send confirmation message
    const sentMessage = await bot.sendMessage(chatId, message, {
        reply_markup: {
            inline_keyboard: [
                [{ text: 'Confirm', callback_data: 'confirm' }],
                [{ text: 'Cancel', callback_data: 'cancel' }]
            ]
        }
    });

    // Listen for user's response
    const callbackListener = async (callbackQuery) => {
        const data = callbackQuery.data;
        const messageId = callbackQuery.message.message_id;

        if (data === 'confirm') {
            // Execute the trade
            try {
                await contract.methods.confirmTrade(token, amountIn, minAmountOut)
                    .send({ from: account.address, gas: 200000 });
                bot.sendMessage(chatId, 'Trade executed successfully.');
            } catch (error) {
                bot.sendMessage(chatId, 'Error executing trade: ' + error.message);
            }
        } else {
            bot.sendMessage(chatId, 'Trade canceled.');
        }

        // Remove the inline buttons
        bot.editMessageReplyMarkup({}, { chat_id: chatId, message_id: messageId });
        bot.removeListener('callback_query', callbackListener);
    };

    bot.on('callback_query', callbackListener);
}

// Listen for TradeDetails event
contract.events.TradeDetails()
    .on('data', async (event) => {
        const { token, amountIn, minAmountOut } = event.returnValues;
        await handleTradeConfirmation(chatId, token, amountIn, minAmountOut);
    })
    .on('error', (error) => {
        console.error('Error listening to TradeDetails event:', error);
    });

console.log('Bot is running...');

THIS IS A ERROR MESSAGE I GOT TRYING TO RUN IT:

/Users/j/MyTelegramBot/index.js:46
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
^^^^^

SyntaxError: Unexpected token ‘const’
at wrapSafe (node:internal/modules/cjs/loader:1281:20)
at Module._compile (node:internal/modules/cjs/loader:1321:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
at Module.load (node:internal/modules/cjs/loader:1208:32)
at Module._load (node:internal/modules/cjs/loader:1024:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
at node:internal/main/run_main_module:28:49

THIS IS MY .ENV FILE

 TELEGRAM_BOT_TOKEN=
    INFURA_OR_ALCHEMY_ENDPOINT=
    CONTRACT_ADDRESS=
    PRIVATE_KEY=
    TELEGRAM_CHAT_ID=

——————————————————————–THIS IS THE TEST CODE THAT I USED TO TEST THE BOT.

test('basic arithmetic', () => {
  expect(1 + 2).toBe(3);
});

Is it possible to see a complete list of const or let variables?

I’m writing a piece of JavaScript code which will be used on any Instagram POSTS page (the landing page of an Instagram user). After pasting my code into the console and hitting Enter, the code needs to get all posts that have been loaded.

I noticed that, after scrolling down the page for some distance, the previously loaded posts disappear from DOM. And after scrolling back up, those posts re-appear in DOM. I think the data of those posts are most likely stored in a variable for quick access because I have seen a similar social media doing that.

I checked the window global variable and didn’t find any such variable under it. The variable (if there is one) must have been a const or let variable then. Is there a way to see a complete list of const or let variables so that I can try to dig out the data of posts from them?

Call javascript function from Swift in Capacitor

I completed the capacitor iOS example by packaging a web game (Phaser). It runs fine but I would like to know how to call into a javascript function in the game from native Swift code. I see an extended WKWebView in the capacitor pod but I don’t see how it’s used in the app. I need to do the same in android but I’ll do that in another post.

Any thoughts?