AWS Role Assume Role Temporary Access with Java-Script for backend

In the past I open an minio client inside my Java-Script app with a technical user to access S3. This was working very good. Now I want ot make the app more secure. My app is running inside a ECS Cluster on a Fargate service/task.

I have a task role with “S3 Full Access” that was given to the Bucket with s3Bucket.grantReadWrite(props.role);

I assume that the task role with S3 Full Access can access the bucket without accesskey and secretkey from technical user.
I try to use the function “AsumeRoleProvider”. But iam confused how to get the webidentityToken and why the function also request an accesskey and secretkey?

My task role has the sts:AssumeRole in Trusted entities

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ecs-tasks.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

The attached image to try to use currently.Function I use currently

I think the appoach to access S3 from ECS task is wrong. Anybody has an hint ot a weblink where I can see how this have to work?

TypeScript throwing many errors about “IntrinsicAttributes” e.g. “Property ‘placeholder’ does not exist on type ‘IntrinsicAttribute'”

I’m trying to implement a data table from shadcn-ui, and I can’t seem to get it working without numerous TypeScript errors that don’t allow me to deploy to Vercel. It works perfectly fine on the development server.

Here’s my data-table.tsx, which has other things like pagination and search.

"use client"

import * as React from "react"
import {
  ColumnDef,
  ColumnFiltersState,
  SortingState,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"



interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[]
  data: TData[]
}

export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
    []
  )

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    onSortingChange: setSorting,
    getSortedRowModel: getSortedRowModel(),
    onColumnFiltersChange: setColumnFilters,
    getFilteredRowModel: getFilteredRowModel(),
    state: {
      sorting,
      columnFilters,
    },
  })

  return (
    <div>
      <div className="flex items-center py-2">
        <Input
          placeholder="Search for summary..."
          value={(table.getColumn("title")?.getFilterValue() as string) ?? ""}
          onChange={(event) =>
            table.getColumn("title")?.setFilterValue(event.target.value)
          }
          className="max-w-sm"
        />
      </div>
      <div className="rounded-md border">
        <Table>
          <TableHeader>
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header) => {
                  return (
                    <TableHead key={header.id}>
                      {header.isPlaceholder
                        ? null
                        : flexRender(
                            header.column.columnDef.header,
                            header.getContext()
                          )}
                    </TableHead>
                  )
                })}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody>
            {table.getRowModel().rows?.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow
                  key={row.id}
                  data-state={row.getIsSelected() && "selected"}
                >
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell colSpan={columns.length} className="h-24 text-center">
                  No results.
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>
      <div className="flex items-center justify-end space-x-2 py-2">
        <Button
          variant="link"
          size="sm"
          onClick={() => table.previousPage()}
          disabled={!table.getCanPreviousPage()}
        >
          Previous
        </Button>
        <Button
          variant="link"
          size="sm"
          onClick={() => table.nextPage()}
          disabled={!table.getCanNextPage()}
        >
          Next
        </Button>
      </div>
    </div>
  )
}

Heres my columns.tsx, which has all my columns for the data table.

"use client"

import { ColumnDef } from "@tanstack/react-table"
import { MoreVertical } from "lucide-react"
 
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import Link from "next/link"

// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type Video = {
  id: string
  title: string
  uploaddate: Date
}

export const columns: ColumnDef<Video>[] = [
    
  {
    accessorKey: "title",
    header: "Title",
    cell: ({ row }) => {
      return <Link href={`/dashboard/summaries/${row.original.id}/`} className="text-underline">{row.getValue("title")}</Link>
    },
  },
  {
    accessorKey: "uploaddate",
    header: "Upload Date",
    cell: ({ row }) => {
      const ud = new Date(row.getValue("uploaddate"))
      const formatted = ud.toLocaleDateString()
 
      return <div className="text-right font-medium">{formatted}</div>
    },
  },
  {
    id: "actions",
    cell: ({ row }) => {
      const video = row.original
 
      return (
        <DropdownMenu>
          <DropdownMenuTrigger>
            <Button variant="ghost" className="h-8 w-8 p-0">
              <MoreVertical className="h-4 w-4" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuLabel>Actions</DropdownMenuLabel>
            <DropdownMenuItem
              /*onClick={() => navigator.clipboard.writeText(payment.id)}*/
            >
                <Link href={`/dashboard/summaries/${video.id}/generate`}>Generate new summary</Link>
              
            </DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem>View customer</DropdownMenuItem>
            <DropdownMenuItem>View payment details</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      )
    },
  },
]

The main error it’s throwing is Property 'xx' doesn't exist on type 'IntrinsicAttribute' or Type '{ children: Element[]; }' has no properties in common with type 'IntrinsicAttribute'

Any help is much appreciated!

viewport does not push up with on screen keyboard on iOS safari

I have a React based pwa with a textarea input. On my own device (Andorid chrome and FF), tapping the textarea pops up the onscreen keyboard and it pushes all content upwards as if it is adding margin-bottom: <height of keyboard>px. This is default behavior which I want to retain. But on some other people’s devices, this doesn’t happen. The keyboard pops up but does not push the content upwards. How can I make the keyboard push content upwards? AFAIK this is not happening on the following:

  • Android Chromium
  • iOS safari

There are many SO posts about stopping the keyboard from pushing the viewport up. But I have found no posts about retaining or enabling the keyboard to push content up.

TypeError : a is not iterable

const a= [1,2,3,4,5,6,7,8,9,10];
function evenNum (a){
    for (let element of a){
        if (element%2===0){
            console.log(element);
        }
    }
};

console.log(oddNum());


function oddNum (a){
    for (let element of a){
        if (element%2!=0){
            console.log(element);
        }
    }
};

console.log(evenNum([1,2,3,4,5,6,7,8,9,10]))

Learning javascript as a complete beginner to programming in general. As I was following this video text in this “exercise” we wanted to display only the odd and even numbers in the array.

While the second function works ok, I don’t understand why can’t I declare an array before the evenNum function and use the array as a parameter of the next function.

Was expecting the same results as the function below.

Why doesn’t localstorage show me the current version?

Here is the code:



<div class="roth_allgemein">
    <h2>Notizen</h2>
    <div class="Notizen">
        <textarea id="textarea"></textarea>
    </div>
      <button class="Absenden" id="speichern" onclick="fixTextarea()"><b>Speichern</b></button>
      <button class="Absenden" id="bearbeiten" onclick="fixTextarea()"><b>Bearbeiten</b></button>
    </div> 
   
  </div>
  <script src="test.js"></script>



function fixTextarea() {
    let textArea_ = document.getElementById("textarea");
    let speichernFix = document.getElementById("speichern");
    let bearbeitenFix = document.getElementById("bearbeiten");

    // Event listener for saving
    speichernFix.addEventListener("click", function() {
        textArea_.setAttribute("readonly", true);
        textArea_.style.outline = "1px solid green";  
        textArea_.style.border = "none"; 
        localStorage.setItem("textareaContent", textArea_.value); // Inhalt speichern
    });

    // Event listener for editing
    bearbeitenFix.addEventListener("click", function() {
        textArea_.removeAttribute("readonly");
        textArea_.style.outline = "1px solid green"; 
    });

    // Retrieve and play content from localStorage
    if (localStorage.getItem("textareaContent")) {
        textArea_.value = localStorage.getItem("textareaContent");
    }
}


document.addEventListener("DOMContentLoaded", fixTextarea);

I would like to create a field where the user can write something. As soon as you press the “Speichern” button, the text should no longer be editable. Only possible again with the “Bearbeiten” button. I always want to save the current result in the LocalStorage. However, it always shows me the text of the “Speichern” button. As soon as I change the text and press reload, it is deleted and the first/old result is displayed again. Does anyone have an idea how I could solve this? I’ve tried so many different variations, but I can’t get the result I want. Thanks a lot.

Storing my API Keys in a PHP file inside of my “public_html” Hostgator folder for my website: Is this secure? Or can prying eyes access its contents?

I know the conventional wisdom is, never store API keys in the frontend — instead always store this on the server-side. My programming / web development up to this point has all been pretty simple stuff, to the degree that I’ve never really needed to use secret API keys or info like this that needs to be hidden. Everything has basically just been HTML / CSS / JS.

My initial thinking was — “ok, store it on the backend means, like when i have a database and there’s that code that runs when you send a request to the database, i can store the API keys inside of there, since that’s like a hidden black box that people can’t access.”

Now it appears another option is, I can have other filetypes on my Hostgator website, where those filetypes will remain hidden/secured, to where nobody can access the actual interiors of the files. So in my websites public_html HTML/CSS/JS frontend files, I could send Javascript requests to those PHP files, and use the outputs as needed — but nobody could access and actually see the contents of those PHP files.

Is my understanding of how this all works correct?

Updating `dayCellContent` with contents of events with FullCalendar

I want to update a cells header either based on an event, so looking for a special string, or through some other way to send in data from an API. This would be something that is unique to each day.

I was able to accomplish this with dayCellDidMount by looking at arg.view.calendar.getEvents()

The problem is that it seems like dayCellDidMount runs before the events are pulled, so this method and my custom header only works when I switch months or to other views. But on page load it does not work. Running into a similar issue trying to use dayCellContent

I am using FullCalendar 6.1.10

dayCellDidMount: function(arg) {
                alert("Debug: day cell did mount called");

                var weightUtilization = arg.view.calendar.getEvents().find(event =>
                    event.extendedProps.eventTitle.includes("Weight Utilization") &&
                    event.start.toDateString() === arg.date.toDateString()
                );
                
                if (weightUtilization) {
                    alert("Found weightUtilization")
                }
            },

This is a cut down version of what I have, when I first load the page the first alert will properly trigger but the second will not. In the API every day has this unique event.

When I switch to another month or switch to week view, the second alert will properly trigger since the events are there now. and the part of the code (which is not in this example) that actually updates the header will work and I will see what I am looking for.

So how would I make sure this method would run after events are loaded?

sorting array of object 4 times by specific type

Is there any way to sort the items as shows in the examples?
In the examples i show how the objects must be sorted based the type.

// don't sort anything if typeA is 'p' always the 'p' must be on top

[{typeA: 'p', typeB: '', typeC: 8, typeD: 'N'}]
[{typeA: 'p', typeB: '', typeC: 0, typeD: 'C'}]
[{typeA: 'p', typeB: '', typeC: 10, typeD: 'O'}]
[{typeA: 'p', typeB: '', typeC: 3, typeD: 'H'}]
[{typeA: 'p', typeB: '', typeC: 0, typeD: 'H'}]
[{typeA: 'p', typeB: '', typeC: 5, typeD: 'N'}]
[{typeA: 'p', typeB: '', typeC: 1, typeD: 'A'}]
// result N,C,O,H,H,N,A
// if typeB exist 't' sort typeB by typeC numerical order

[{typeA: '', typeB: 't', typeC: 10, typeD: 'O'}]
[{typeA: '', typeB: 't', typeC: 8, typeD: 'N'}]
[{typeA: '', typeB: 't', typeC: 5, typeD: 'N'}]
[{typeA: '', typeB: 't', typeC: 3, typeD: 'H'}]
[{typeA: '', typeB: 't', typeC: 1, typeD: 'A'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'C'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'M'}]
//result O,N,N,H,A,C,M 
// if typeB exist 't' and typeC = 0 sort typeB by typeD

[{typeA: '', typeB: 't', typeC: 0, typeD: 'A'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'C'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'H'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'N'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'N'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'M'}]
[{typeA: '', typeB: 't', typeC: 0, typeD: 'O'}]
//result A,C,H,N,N,M,O 

Notice that in the array of objects maybe exists and typaA ‘p’ and typeB ‘t’ ex:

[{typeA: 'p', typeB: '', typeC: 8, typeD: 'N'}]
[{typeA: 'p', typeB: '', typeC: 0, typeD: 'C'}]
[{typeA: '', typeB: 't', typeC: 10, typeD: 'O'}]
[{typeA: 'p', typeB: '', typeC: 3, typeD: 'H'}]
[{typeA: 'p', typeB: '', typeC: 0, typeD: 'H'}]
[{typeA: '', typeB: 't', typeC: 5, typeD: 'N'}]
[{typeA: 'p', typeB: '', typeC: 1, typeD: 'A'}]
//result N,C,H,H,A,O,N
    for (let i = 0; i < items.length; i++) {
        var list = document.getElementById('holder');
        [...list.children]
            .sort // sort it here as we want and put it in the list
            .forEach(node => list.appendChild(node));
    }

Thanks in advance.

Javascript/Jquery get value from object

How do ik place “price_per” in a new Var (above this script)

<script type="text/x-magento-init">
{
    ".price": {
        "Aitoc_ProductUnitsAndQuantities/js/productunitsandquantities": {"mode":"product","replace_qty":"0","qty_type":"0","use_quantities":"1,2,3,4,5,6,7,8,9,10","start_qty":"1","qty_increment":"2","end_qty":"10","allow_units":"0","price_per":"Hoppah","price_per_divider":"Jaja"}        }
}
</script>

Vaadin alternative to window.function = funtion() {}

This is an extension to this question


For a couple of months, I am writing JavaScript functions that I constantly run using my Vaadin components with method executeJs().

UI.getCurrent().getPage().executeJs("myFunction()");

So am I wondering if there are other alternative ways of exporting JS functions from .js files, other than:

window.myFunction = function myFunction() {
   ....
}

I tried to export the function, by importing the file itself, using both annotations @JsModule and @JavaScript, but without any success.

@PageTitle("Dashboard")
@JavaScript("./themes/light_theme/components/javascript/myFile.js")
public class DashboardView extends Div {

    public DashboardView() {
        UI.getCurrent().getPage().executeJs("myFunction()");
    }

}

client undefined, can’t connect to database with mongodb driver

I have a node app and when I add my routes: app.use(‘/api’, routes), the app crashes, without this line the app runs.

The error is: return db.collection(name)
^
TypeError: Cannot read properties of undefined (reading ‘collection’)

because db is undefined.

index.ts:

import express from 'express'
import cors from 'cors'
import routes from './routes'
import { connectDB } from './db'
const port= process.env.port|| 5000
const app = express()

app.use(cors())
app.use(express.json())
app.use('/api', routes)
app.get('/', (req, res) => res.send('Running'))    

connectDB().then(res => {
    app.listen(port, () => console.log(`Running: http://localhost:${port}`))
}).catch(err => console.log(err))

db.ts:


let db: Db
    
export const connectDB = async (): Promise<void> => {
  try {
    const uri = process.env.MONGO_URI as string
     const client = new MongoClient(uri)
    await client.connect()   
    db = client.db(process.env.DB_NAME)
  }catch(error) {
    console.log(error)
    
  }
}

export const getCollection = <T extends Document>(name: string): Collection<T> => {
  return db.collection<T>(name)
}

‘/routes/index.ts’:

import { Router } from 'express'
import productRoutes from './products/productRoutes'

const router = Router()

router.use('/products', productRoutes )

export default router

productRoutes.ts:

import express from 'express'
import { createProduct } from '../../agents/product/productAgent';

router.post('/', async (req, res) => {
    try {
      const success = await createProduct(req.body);
      res.status(success ? 201 : 400).json({ success });
    } catch (error: any) {
      res.status(500).json({ error: error.message });
    }
  })

productAgent.ts:

import { getCollection } from '../../db'
import { ObjectId } from 'mongodb'
import { IProduct } from '../../types/IProduct'

const collectionProduct = getCollection<IProduct>('products')

export const createProduct = async (parameters: IProduct): Promise<boolean> => {
    try {
     const res= await collectionProduct.insertOne(parameters)
     return res.acknowledged
    } catch (error) {
        throw new Error('Error create product')
    }
}

I can’t figure out what’s wrong and how adding ‘app.use(‘/api’, routes)’ to my main file affects my database connection.

Adding User Data To Socket In NestJS Guard

I have a guard for mijn Gateway and want to add a user’s data to a socket so that i can access the data in the gateway’s handlers but am having no success. This is what i have:

@Injectable()
export class MySocketAuthGuard implements CanActivate {

canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
// Fetching user data and other stuff are removed for clarity.

let socket = context.switchToWs().getClient<Socket>();
// "user" is an attribute am adding to socket
socket.user = new User(userId);
return true.
}

}

In mijn Gateway handlers i don’t get any user property on the Socket. The user property doesn’t even exist on the socket.

export class ChannelGateway implements OnGatewayConnection, OnGatewayDisconnect {

    @UseGuards(MySocketAuthGuard)
        handleConnection(@ConnectedSocket() socket: Socket) {
    console.log(socket.user);
    }
}

What am i doing wrong?

Any pointers will be appreciated.

How to replace texts in PDF?

For my project, I need to replace texts in PDF with JS. I made progress but PDF outputs of professional programs like Word or LibreWriter didn’t have any understandable and replacable text. What do I need to do?

basic raw PDF file (just a section):
4 0 obj
<< /Length 132 >>
stream
BT
/F1 12 Tf
50 150 Td
(This is a simple PDF) Tj
0 -20 Td
/F2 12 Tf
(This is bold text) Tj
0 -20 Td
/F3 12 Tf
(This is italic text) Tj
ET
endstream
endobj

at above we can see texts easily but PDF’s of Word, etc. didn’t have real text. I need to know how to parse the files. Any articles or help will be helpful thank you so much for reading.

I tried to parse and replace with fs stream, with constant texts it is possible but with inputs come from other files or user is not working. Here is the basic code:

const fs = require('fs');
const path = require('path');

var pdfData = null;
let parsedText = null;
let fontMap = {};


function readPDFFile(filePath) {
    try {
        pdfData = fs.readFileSync(filePath, 'utf8');
        return pdfData;
    } catch (err) {
        console.error(`Could not read the PDF file: ${err.message}`);
        return null;
    }
}

function parsePDF() {
    if (!pdfData) {
        console.error('No PDF data available.');
        return null;
    }

    const lines = pdfData.split('n');
    const text = [];
    fontMap = {};

    let inStream = false;
    let currentFont = null;

    lines.forEach(line => {
        line = line.trim();

        if (line === "stream") {
            inStream = true;
        } else if (line === "endstream") {
            inStream = false;
        } else if (line.startsWith('/BaseFont')) {
            const match = //BaseFonts/(w+)(?:-Bold|-Oblique)?/.exec(line);
            if (match) {
                currentFont = match[1];
                fontMap[currentFont] = match[0];
            }
        } else if (inStream) {
            const match = /((.*)) Tj/.exec(line);
            if (match) {
                text.push({ text: match[1], font: currentFont });
            }
        }
    });

    parsedText = text;
    return parsedText;
}

function processParsedText(style) {
    if (!parsedText) {
        console.error('No parsed text available.');
        return null;
    }

    const styleMap = {
        Italic: '-Oblique',
        Bold: '-Bold'
    };

    if (!styleMap[style]) {
        console.error('Invalid style provided.');
        return null;
    }

    parsedText = parsedText.map(item => {
        if (item.font) {
            item.font = `${item.font}${styleMap[style]}`;
        }
        return item;
    });

    return parsedText;
}

function replace(parsedText, newText) {
    if (!parsedText) {
        console.error('No parsed text provided.');
        return null;
    }

    if (!newText || newText.length !== parsedText.length) {
        console.error('Invalid new text provided.');
        return null;
    }

    const newContent = parsedText.map((item, index) => ({
        text: newText[index],
        font: item.font
    }));

    let updatedPDF = pdfData;
    parsedText.forEach((item, index) => {
        const regex = new RegExp(`\(${item.text}\) Tj`, 'g');
        updatedPDF = updatedPDF.replace(regex, `(${newContent[index].text}) Tj`);
    });

    pdfData = updatedPDF;

    return newContent;
}

function saveToFile(filename) {
    if (!pdfData || !parsedText) {
        console.error('No data available.');
        return;
    }

    const combinedContent = `${pdfData}`;
    fs.writeFileSync(filename, combinedContent, 'utf8');
}

function processPDF(inputFilePath, outputFilePath) {
    readPDFFile(inputFilePath);
    parsePDF();
    saveToFile(outputFilePath);
}

module.exports = {
    readPDFFile,
    parsePDF,
    processParsedText,
    replace,
    saveToFile,
    processPDF,
    getPdfData: () => pdfData,
    getParsedText: () => parsedText
};

Javascript New worker only from cache

The stockfish chess engine is 64MB big.
I need to ensure that nobody downloads this over a network connection.
(only allow over wifi or ethernet)

I am running this code to check if the connection is cellular and if the file is not already in the cache.If so, don’t use the big file, otherwise, use it:

function LoadEngine() {
if(navigator.connection.type=='cellular'&&!IsCached) return;
stockfish=new Worker('//www.mysite.com/stockfish-16.1-single.js')
}

IsCached is global and is set beforehand with this code:

async function SetCached()
{
try {
await fetch('//www.linguashop.com/course/java/stockfish-16.1-single.js',{
method:'Head',cache:'only-if-cached',mode:'same-origin'});
IsCached=true;
} 
catch (error) {IsCached=false}
}

Testing indicated that the logic worked ok.
On a mobile, cellular was detected and whether or not the file was in the cache was also detected ok.

And yet…the data usage clearly indicated that the big file had been downloaded.
(i.e. the cached file was not used).

Is there is a reliable way of only using a cache file for new worker and not allowing a download.

i.e.:

stockfish=new Worker('//www.mysite.com/stockfish-16.1-single.js','cache-only');
stockfish=new Worker('//www.mysite.com/stockfish-16.1-single.js','no-download');

How to check if two values ​match in different “google sheets” with google apps script?

I’ve been building a script for a few days which I wanted to do the following:

  1. From a database (generated from a forms) collect specific data from the students (I’m going to high school)

  2. Based on a template, from a different document, fill it with the students’ data that’s been collected

  3. And when the time comes to check which teacher they have, if the data (of the student) of the course they are in and the classroom to which they belong coincide with those of any of the teachers in another database ( in a different Google Sheets), an email has to be sent to the teacher because of they be able to see the document with their specific students’ data

​ var templateCopy= template.makeCopy("ficha_individual: " + actualSheet.getRange("C" + fila).getValue());

var document = SpreadsheetApp.openById(templateCopy.getId());

var course = actualSheet.getRange("L" + fila).getValue();

var class = actualSheet.getRange("M" + fila).getValue();

var teachersheets = SpreadsheetApp.openById("IDFORMTHETEACHERSHEET");

var lastRow = teachersheets .getLastRow();

var teachercourse= teachersheets.getRange("D2:D" + lastRow).getValues();

var teacherclass= teachersheets.getRange("E2:E" + lastRow).getValues();

var teacherMail= teachersheets.getRange("B2:B" + lastRow).getValues();

if (course && class == teachercourse && teacherclass) {
document.addEditor(teacherMail)} 

else { ui.alert("There's no teacher for the students") }

​The problem is that I don’t quite understand how to go through the rows and columns of the spreadsheet in which the teachers’ data is found in order to see if it matches with the students data.

I principaly want that it sends an Email to the one that is registered from the forms if the data from the same row on the besides columns matches