Datei mit Google Apps Script auf mein Google Drive hochladen (KEIN FORMULAR IN GOOGLE)

Lesezeit: 17 Minuten

Benutzer-Avatar
Marcel Dz

Also im Grunde ist die Aufgabe ganz einfach, aber ich habe keine praktikable Lösung für mein Problem gefunden. Ich habe ein riesiges Upload-Skript auf meiner Website (im Moment localhost), aber reduzieren wir die Komplexität auf das einzig Notwendige.

Ich möchte also nur eine einzelne Datei mit Google App Script auf Google Drive hochladen und die URL davon erhalten, um sie in einer var zu speichern, um mit diesen Informationen zu einem späteren Zeitpunkt in meiner Funktion zu arbeiten.

Jetzt ist das Problem, dass ich das Formular bereits auf meiner Website habe, ich möchte das Formular nicht in script.google.com als zusätzliches HTML, ich möchte meine Benutzereingaben an Google App Script übertragen, es dann auf Google Drive hochladen und die URL zurückgeben zurück zu meiner Website, wo ich es in einer var speichern kann.

Mein Problem ist jetzt, dass ich nicht alles zusammenbauen kann.

Dies ist das Formular auf meiner Website (vereinfacht):

<form name="myForm" method="post">
            <!-- <form name="first-form"> -->

  <input type="text" placeholder="Name" id="myName">
  <input type="file" name="myFile" id="myFile">
  <button onclick="UploadFile()" type="submit">submit</button>

</form>

Wie kann ich also meine Informationen in Google Drive hochladen und ein Ergebnis zurückerhalten? Wie kann ich die Daten in Google App Script pushen, ohne iFrame oder etwas anderes zu verwenden?

DANKE!

**** Arbeitsbeispiel, wenn HTML in scripts.google.com ist ****

gs

function doGet(e) {
  return HtmlService.createHtmlOutputFromFile('forms.html').setTitle("Google File Upload by CTRLQ.org");
}


function uploadFileToGoogleDrive(data, file, name, email) {
  
  try {
    
    var dropbox = "Received Files";
    var folder, folders = DriveApp.getFoldersByName(dropbox);
    
    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }
    
    /* Credit: www.labnol.org/awesome */
    
    var contentType = data.substring(5,data.indexOf(';')),
        bytes = Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)),
        blob = Utilities.newBlob(bytes, contentType, file),
        file = folder.createFolder([name, email].join(" ")).createFile(blob);
    
    return "OK";
    
  } catch (f) {
    return f.toString();
  }
  
}

html in apps.googlescript

<!DOCTYPE html>
<html>
  <head>
    <base target="_blank">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Google File Upload by CTRLQ.org</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
    <style>
      .disclaimer{width: 480px; color:#646464;margin:20px auto;padding:0 16px;text-align:center;font:400 12px Roboto,Helvetica,Arial,sans-serif}.disclaimer a{color:#009688}#credit{display:none}
    </style>
  </head>
  <body>

    <!-- Written by Amit Agarwal [email protected] --> 

    <form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
      <div id="forminner">
        <div class="row">
          <div class="col s12">
            <h5 class="center-align teal-text">Upload Files to my Google Drive</h5>
            <p class="disclaimer">This <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/">File Upload Form</a> (<a href="https://youtu.be/C_YBBupebvE">tutorial</a>) is powered by <a href="https://ctrlq.org/code/19747-google-forms-upload-files" target="_blank">Google Scripts</a></p>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12">
            <input id="name" type="text" name="Name" class="validate" required="" aria-required="true">
            <label for="name">Name</label>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12">
            <input id="email" type="email" name="Email" class="validate" required="" aria-required="true">
            <label for="email">Email Address</label>
          </div>
        </div>

        <div class="row">
          <div class="file-field input-field col s12">
            <div class="btn">
              <span>File</span>
              <input id="files" type="file">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path validate" type="text" placeholder="Select a file on your computer">
            </div>
          </div>
        </div>

        <div class="row">
          <div class="input-field col s6">
            <button class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
          </div>   
        </div>
        <div class="row">
          <div class="input-field col s12" id = "progress">
          </div>
        </div>
      </div>
      <div id="success" style="display:none">
        <h5 class="left-align teal-text">File Uploaded</h5>
        <p>Your file has been successfully uploaded.</p>
        <p>The <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/">pro version</a> (see <a href="">demo form</a>) includes a visual drag-n-drop form builder, CAPTCHAs, the form responses are saved in a Google Spreadsheet and respondents can upload multiple files of any size.</p>    
        <p class="center-align"><a  class="btn btn-large" href="https://gum.co/GA14?wanted=true" target="_blank">Upgrade to Pro</a></p>
      </div>
    </form>

    <div class="fixed-action-btn horizontal" style="bottom: 45px; right: 24px;">
      <a class="btn-floating btn-large red">
        <i class="large material-icons">menu</i>
      </a>
      <ul>
        <li><a class="btn-floating red"  href="https://gum.co/GA14" target="_blank" title="Buy License - File Upload Form"><i class="material-icons">monetization_on</i></a></li>
        <li><a class="btn-floating blue"  href="https://youtu.be/C_YBBupebvE" target="_blank" title="Video Tutorial"><i class="material-icons">video_library</i></a></li>
        <li><a class="btn-floating green" href="http://www.labnol.org/internet/file-upload-google-forms/29170/" target="_blank" title="How to Create File Upload Forms"><i class="material-icons">help</i></a></li>
      </ul>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
    <script src="https://gumroad.com/js/gumroad.js"></script>

    <script>

      var file, 
          reader = new FileReader();

      reader.onloadend = function(e) {
        if (e.target.error != null) {
          showError("File " + file.name + " could not be read.");
          return;
        } else {
          google.script.run
            .withSuccessHandler(showSuccess)
            .uploadFileToGoogleDrive(e.target.result, file.name, $('input#name').val(), $('input#email').val());
        }
      };

      function showSuccess(e) {
        if (e === "OK") { 
          $('#forminner').hide();
          $('#success').show();
        } else {
          showError(e);
        }
      }

      function submitForm() {

        var files = $('#files')[0].files;

        if (files.length === 0) {
          showError("Please select a file to upload");
          return;
        }

        file = files[0];

        if (file.size > 1024 * 1024 * 5) {
          showError("The file size should be < 5 MB. Please <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/" target="_blank">upgrade to premium</a> for receiving larger files in Google Drive");
          return;
        }

        showMessage("Uploading file..");

        reader.readAsDataURL(file);

      }

      function showError(e) {
        $('#progress').addClass('red-text').html(e);
      }

      function showMessage(e) {
        $('#progress').removeClass('red-text').html(e);
      }


    </script>

  </body>

</html>

Wie empfohlen werde ich den Prozess hier beschreiben.

Wir sind also auf der Website: www.beispiel.com , gibt es ein Formular mit Texteingabefeld und Dateifeld. Nehmen wir an, wir fügen ein Bild ein und nennen es Beispiel. Wenn wir jetzt auf „Senden“ drücken, möchte ich das Bild ohne oAuth auf Google Drive hochladen (deshalb müssen wir hier das Google-App-Skript verwenden) und es so benennen, wie wir es in das Textfeld eingegeben haben. Wenn der Upload abgeschlossen ist, möchte ich, dass die URL des Bildes von Google Drive an die Website zurückgegeben wird, damit das Formular mit den Informationen weiterarbeiten kann. Ich möchte die zurückgegebene URL dann in einer Var speichern, um sie später in einer Datenbank zu speichern. Deshalb brauche ich das Ergebnis zurück auf meine Website.

Das Schema sieht also wie folgt aus:

Geben Sie Informationen zum Formular auf der Website ein -> Umgeleitet zum Google App-Skript: Nehmen Sie die Informationen aus dem Website-Formularfeld und laden Sie die Datei auf Google Drive hoch und benennen Sie sie wie eine Texteingabeeingabe -> URL von Google Drive als Endergebnis verwenden -> Endgültiges URL-Ergebnis zurückleiten zur Website -> URL-Ergebnis in var speichern und mit der Funktion auf der Website fortfahren -> am Ende die Informationen aus var in einer Datenbank speichern -> fertig

———————————————— BEARBEITEN: ——————

Dank @Tanaike bin ich dem Ziel meiner Herausforderung hier viel näher gekommen. Um zu sehen, wo ich hängengeblieben bin, repliziere ich jetzt mein Problem:

Ich habe das Formular mit dem Skript aus Ihrem Beispiel übernommen:

<form id="form">
  <input name="file" id="uploadfile" type="file">
  <input name="filename" id="filename" type="text">
  <input id="submit" type="submit">
</form>
<script>
const form = document.getElementById('form');
form.addEventListener('submit', e => {
  e.preventDefault();
  const file = form.file.files[0];
  const fr = new FileReader();
  fr.readAsArrayBuffer(file);
  fr.onload = f => {
    
    const url = "https://script.google.com/macros/s/###/exec";  // <--- Please set the URL of Web Apps.
    
    const qs = new URLSearchParams({filename: form.filename.value || file.name, mimeType: file.type});
    fetch(`${url}?${qs}`, {method: "POST", body: JSON.stringify([...new Int8Array(f.target.result)])})
    .then(res => res.json())
    .then(e => console.log(e))  // <--- You can retrieve the returned value here.
    .catch(err => console.log(err));
  }
});
</script>

und für Googlescript:

function doPost(e) {
  // const folderId = "###";  // Folder ID which is used for putting the file, if you need.

  const blob = Utilities.newBlob(JSON.parse(e.postData.contents), e.parameter.mimeType, e.parameter.filename);
  const file = DriveApp.getFolderById(folderId || "root").createFile(blob);
  const responseObj = {filename: file.getName(), fileId: file.getId(), fileUrl: file.getUrl()};
  return ContentService.createTextOutput(JSON.stringify(responseObj)).setMimeType(ContentService.MimeType.JSON);
}

Als ich nun versuchte, etwas hochzuladen, hatte ich folgenden Fehler: CORS-Richtlinie konnte nicht abgerufen werden. Also habe ich diesen Teil wie folgt geändert und den Modus no cors hinzugefügt:

const qs = new URLSearchParams({filename: form.filename.value || file.name, mimeType: file.type});
        fetch(`${url}?${qs}`, {method: "POST", mode: "no-cors", body: JSON.stringify([...new Int8Array(f.target.result)])})

Das hat funktioniert. Beim zweiten Versuch, die Datei hochzuladen, wurde der folgende Fehler verursacht: Es heißt: syntax error: unexpected end of input

Also habe ich diese Zeile geändert und die Klammern aus res.json entfernt

JSON.stringify([...new Int8Array(f.target.result)])})
        .then(res => res.json)

Der dritte Versuch, die Datei hochzuladen, funktionierte tatsächlich mit folgendem Konsolenergebnis:

ƒ json() { [native code] }

Es wird jedoch keine Datei in Google Drive hochgeladen. Irgendwo fehlt mir etwas. Vielleicht sollten wir einen Ordner erstellen und die Dateien dort ablegen.

Oh und noch eine Information: Wenn ich die doPost-Funktion im Google App-Sript ausführe, heißt es:

TypeError: Cannot read property 'postData' of undefined (line 13

BEARBEITEN2 —————————————–

Ich fügte hinzu https://drive.google.com/uc?export=download&id=###fileId### zu Ihrem Code und alles funktioniert gut. Die Datei wird hochgeladen.

Nehmen wir an, wir laden die Datei test.mp3 hoch und nennen sie testdata. Das erhalten wir:

{
  "filename": "testdata",
  "fileId": "###some id##",
  "fileUrl": "https://drive.google.com/uc?export=download&id=###fileId###"
}

Wenn ich jetzt die Datei-URL öffne, lädt der Browser die Datei herunter, aber sie heißt: testdata, nicht testdata.mp3. Die Dateityp-Endung fehlt.

Zweite Aufgabe: Wenn Sie auf den Link klicken, möchte ich die Datei im Browser öffnen, wenn es sich beispielsweise um eine MP3-Datei handelt, möchte ich, dass Sie den Sound in der Webansicht abspielen können, wie hier: https://files.freemusicarchive.org/storage-freemusicarchive-org/music/Creative_Commons/Dead_Combo/CC_Affiliates_Mixtape_1/Dead_Combo_-_01_-_Povo_Que_Cas_Descalo.mp3

Ich hoffe, Sie können mich anleiten!

  • Hör zu: developer.google.com/picker/docs

    – Kos

    12. August 2020 um 12:56 Uhr

  • Vielen Dank für den Link, soweit ich weiß, benötigen Sie die oAuth-Authentifizierung, ich brauche einen öffentlichen Upload, daher funktioniert dieser Ansatz bei mir nicht.

    – Marcel Dz

    12. August 2020 um 12:59 Uhr

  • Probieren Sie eine.web-App aus und ich rahme sie in Ihre Website ein

    – Cooper

    12. August 2020 um 13:04 Uhr

  • wie würde das aussehen? Ich brauche ein Ergebnis um meine Website dann in einer var zu speichern, geht das mit einem iframe?

    – Marcel Dz

    12. August 2020 um 13:06 Uhr

  • Das ist etwas schwer nachzuvollziehen. Können Sie einen schrittweisen Prozess des Workflows darstellen? Submit form > data gets posted to x > redirect to y etc?

    – Ich hoffe, das ist hilfreich für Sie

    12. August 2020 um 13:07 Uhr

Benutzer-Avatar
Tanaike

Ich glaube Ihr Ziel wie folgt.

  • Ihre Website ist nicht mit dem Google-Konto verknüpft. Es ist unabhängig.
  • Ihre Website verfügt über ein Formular zum Hochladen einer Datei.
  • Wenn Benutzer das Formular senden, möchten Sie die Datei ohne Autorisierung auf Ihr Google Drive hochladen und die URL der hochgeladenen Datei auf Google Drive zurückgeben.
  • Über “Datenbank”, das ist Ihre Datenbank. Sie werden die abgerufene URL der Datei auf der Clientseite in “Datenbank” einfügen.

In diesem Fall denke ich, dass Ihr Ziel mit den von Google Apps Script erstellten Web Apps erreicht werden kann.

Verwendungszweck:

Bitte führen Sie den folgenden Ablauf durch.

1. Erstellen Sie ein neues Projekt von Google Apps Script.

Beispielskript von Web Apps ist ein Google Apps-Skript. Erstellen Sie also bitte ein Projekt von Google Apps Script.

Wenn Sie es direkt erstellen möchten, greifen Sie bitte auf zu https://script.new/. Falls Sie in diesem Fall nicht bei Google eingeloggt sind, wird die Anmeldemaske geöffnet. Melden Sie sich also bitte bei Google an. Dadurch wird der Skripteditor von Google Apps Script geöffnet.

2. Bereiten Sie das Skript vor.

Bitte kopieren Sie das folgende Skript (Google Apps Script) und fügen Sie es in den Skript-Editor ein. Dieses Skript ist für die Web-Apps.

Serverseitig: Google Apps Script

Bitte legen Sie die Ordner-ID fest, in der Sie die Datei ablegen möchten.

function doPost(e) {
  const folderId = "root";  // Or Folder ID which is used for putting the file instead of "root", if you need.

  const blob = Utilities.newBlob(JSON.parse(e.postData.contents), e.parameter.mimeType, e.parameter.filename);
  const file = DriveApp.getFolderById(folderId).createFile(blob);
  const responseObj = {filename: file.getName(), fileId: file.getId(), fileUrl: file.getUrl()};
  return ContentService.createTextOutput(JSON.stringify(responseObj)).setMimeType(ContentService.MimeType.JSON);
}

3. Stellen Sie Web-Apps bereit.

  1. Öffnen Sie im Skript-Editor ein Dialogfeld mit „Veröffentlichen“ -> „Als Web-App bereitstellen“.
  2. Auswählen “Mir” zum “Führen Sie die App aus als:”.
    • Dadurch wird das Skript als Eigentümer ausgeführt.
  3. Auswählen “Jeder, auch anonym” zum “Wer hat Zugriff auf die App:”.
  4. Klicken Sie auf die Schaltfläche „Bereitstellen“ als neue „Projektversion“.
  5. Öffnen Sie automatisch ein Dialogfeld mit “Autorisierung erforderlich”.
    1. Klicken Sie auf „Berechtigungen prüfen“.
    2. Eigenes Konto auswählen.
    3. Klicken Sie bei „Diese App ist nicht verifiziert“ auf „Erweitert“.
    4. Klicken Sie auf „Gehe zu ### Projektname ###(unsicher)“
    5. Klicken Sie auf die Schaltfläche “Zulassen”.
  6. OK klicken”.
  7. Kopieren Sie die URL von Web Apps. Es ist wie https://script.google.com/macros/s/###/exec.
    • Wenn Sie das Google Apps-Skript geändert haben, stellen Sie es bitte erneut als neue Version bereit. Dadurch wird das geänderte Skript in Web Apps widergespiegelt. Bitte achten Sie darauf.

4. Laden Sie eine Datei von der Clientseite auf die Serverseite hoch.

Clientseitig: HTML & Javascript

Bitte setzen Sie die URL Ihrer Web-Apps auf das folgende Skript.

<form id="form">
  <input name="file" id="uploadfile" type="file">
  <input name="filename" id="filename" type="text">
  <input id="submit" type="submit">
</form>
<script>
const form = document.getElementById('form');
form.addEventListener('submit', e => {
  e.preventDefault();
  const file = form.file.files[0];
  const fr = new FileReader();
  fr.readAsArrayBuffer(file);
  fr.onload = f => {
    
    const url = "https://script.google.com/macros/s/###/exec";  // <--- Please set the URL of Web Apps.
    
    const qs = new URLSearchParams({filename: form.filename.value || file.name, mimeType: file.type});
    fetch(`${url}?${qs}`, {method: "POST", body: JSON.stringify([...new Int8Array(f.target.result)])})
    .then(res => res.json())
    .then(e => console.log(e))  // <--- You can retrieve the returned value here.
    .catch(err => console.log(err));
  }
});
</script>
  • Wenn Sie auf der Clientseite eine Datei von Ihrem lokalen PC ausgewählt und die Schaltfläche gedrückt haben, wird die Datei auf Ihr Google Drive hochgeladen, indem die Daten von den Web-Apps (Serverseite) abgerufen werden.

Ergebnis:

Wenn das obige Skript ausgeführt wird, wird der folgende Wert zurückgegeben. Daraus können Sie die URL der Datei abrufen.

{
  "filename": "### inputted filename ###",
  "fileId": "###",
  "fileUrl": "https://drive.google.com/file/d/###/view?usp=drivesdk"
}

Notiz:

  • Wenn Sie das Skript von Web Apps geändert haben, stellen Sie die Web Apps bitte erneut als neue Version bereit. Dadurch wird das neueste Skript in Web Apps widergespiegelt. Bitte achten Sie darauf.
  • Im obigen Skript beträgt die maximale Dateigröße 50 MB. Denn in der aktuellen Phase beträgt die maximale Blob-Größe bei Google Apps Script 50 MB.

Verweise:

  • Das ist großartig!! Tausend Dank für diese informative Schritt-für-Schritt-Anleitung! Ich werde es versuchen, wenn ich mit der Arbeit fertig bin, aber was ich bisher durch schnelles Scrollen gesehen habe, gibt es viele relevante Informationen, die Sie mir zur Verfügung gestellt haben, und es scheint, als wäre DIES die perfekte Lösung für meine Herausforderung. Ich kann nur noch einmal sagen, TAUSENDEN DANK AN EUCH!!

    – Marcel Dz

    13. August 2020 um 10:51 Uhr


  • Guten Morgen, ich wollte Sie um ein Feedback bitten. Also habe ich zuerst einen Cors-Richtlinienfehler bekommen, aber ich habe es herausgefunden, indem ich mode: ‘no-cors’ zur Zeile nach dem Abrufen des Posts hinzugefügt habe. Jetzt erhalte ich im Moment einen Syntaxfehler in dieser Zeile: .then(res => res.json()), es heißt unerwartetes Ende der Eingabe

    – Marcel Dz

    14. August 2020 um 6:18 Uhr


  • @ Marcel Dz Vielen Dank für die Antwort. Ich entschuldige mich für die Unannehmlichkeiten. Leider kann ich Ihre Situation nicht nachvollziehen. Denn als ich es getestet habe, konnte ich bestätigen, dass kein Fehler auftritt. Also schlug ich oben vor. Ich entschuldige mich zutiefst dafür. Können Sie die Detailinformationen zur Replikation Ihres aktuellen Problems bereitstellen, um Ihre Situation richtig zu verstehen und Ihre Situation korrekt zu replizieren? Damit möchte ich es bestätigen. Wenn Sie kooperieren können, um Ihr Problem zu lösen, freue ich mich. Können Sie zusammenarbeiten, um Ihr Problem zu lösen? Wenn Sie dies tun können, fügen Sie Ihrer Frage bitte den Detailfluss hinzu.

    – Tanaike

    14. August 2020 um 6:22 Uhr


  • Danke für die schnelle Antwort, ich habe es gerade durch Ändern von .then(res => res.json() in .then( res=> res.json) ohne die Klammern bekommen, es funktioniert. Wenn ich jetzt eine Datei hochlade, erhalte ich etwas etwa so: ƒ json() { [native code] }, aber die Datei wurde noch nicht in das Laufwerk hochgeladen

    – Marcel Dz

    14. August 2020 um 6:24 Uhr

  • @ Marcel Dz Vielen Dank für die Antwort. Ich entschuldige mich für die Unannehmlichkeiten. Leider kann ich Ihre Situation nicht nachvollziehen. Denn als ich es getestet habe, konnte ich bestätigen, dass kein Fehler auftritt. Also schlug ich oben vor. Ich entschuldige mich zutiefst dafür. Können Sie die Detailinformationen zur Replikation Ihres aktuellen Problems bereitstellen, um Ihre Situation richtig zu verstehen und Ihre Situation korrekt zu replizieren? Damit möchte ich es bestätigen. Wenn Sie kooperieren können, um Ihr Problem zu lösen, freue ich mich. Können Sie zusammenarbeiten, um Ihr Problem zu lösen? Wenn Sie dies tun können, fügen Sie Ihrer Frage bitte den Detailfluss hinzu.

    – Tanaike

    14. August 2020 um 6:25 Uhr

Viele nützliche Tipps in https://stackoverflow.com/a/63391363/1585523 Antwort! Ich danke Ihnen für das Teilen. Anstatt die Datei zu POSTen, könnten wir auch verwenden

Auf dem Client: index.html

google.script.run.withSuccessHandler(fileName => {}).withFailureHandler(error => {}).saveInDrive(fileAsByteArray);

Auf dem Server: Code.gs

function saveInDrive(f) {
  const blob = Utilities.newBlob(f, "image/jpeg", "some-name");
  const file = DriveApp.getFolderById("root").createFile(blob);
  return file.getName()
}

Bei diesem Ansatz können Sie sogar komplizierte Typen wie JS-Objekte mit binären Informationen als Werte austauschen.

  • könnten Sie erläutern, wie fileAsByteArray definiert ist?

    – PriyankaJ

    22. Februar um 15:14 Uhr

  • Hängt davon ab, wie Sie die Originaldatei erhalten. Auf Quelle kann Abruf-API sein: zB const fileAsByteArray = new File([Uint8Array.from(await fetchResp)], "myfile.bin"). developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… nimmt in vielerlei Hinsicht Einfluss

    – Nitin

    23. Februar um 7:43 Uhr


1011570cookie-checkDatei mit Google Apps Script auf mein Google Drive hochladen (KEIN FORMULAR IN GOOGLE)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy