diff --git a/Dockerfile b/Dockerfile index e80dad2870d3f917b38aa6b4ea655377bf808738..149d670b74f052834d8d6604edbbdb9c4e94930c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ COPY . . RUN mkdir public/js RUN mkdir public/css RUN yarn install --network-timeout 1000000 -RUN yarn compile +RUN yarn build # |-------------------------------------------------------------------------- # | Install PHP dependencies diff --git a/composer.json b/composer.json index a82125110c168e8c1620f5a7ec212eaef32e3461..1287a32669d41e4683cec684bc4e5fe9f54c3009 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,8 @@ { "require": { "aws/aws-sdk-php": "^3.181", - "guzzlehttp/guzzle": "^7.0" + "guzzlehttp/guzzle": "^7.0", + "webonyx/graphql-php": "^14.11" }, "config": { "vendor-dir": "public/API/vendor" diff --git a/composer.lock b/composer.lock index 6cc263e80a97fab7d510f732f44bdc5bd327f6f1..cea0c4628a65177f7e2af0acb5dba364620385ef 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f47a9b8d286ca72493a7fe02f263976e", + "content-hash": "31a3a0321659f9c8afff63a68a9fafb6", "packages": [ { "name": "aws/aws-crt-php", @@ -669,6 +669,72 @@ } ], "time": "2021-05-27T12:26:48+00:00" + }, + { + "name": "webonyx/graphql-php", + "version": "v14.11.5", + "source": { + "type": "git", + "url": "https://github.com/webonyx/graphql-php.git", + "reference": "ffa431c0821821839370a68dab3c2597c06bf7f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/ffa431c0821821839370a68dab3c2597c06bf7f0", + "reference": "ffa431c0821821839370a68dab3c2597c06bf7f0", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "^7.1 || ^8" + }, + "require-dev": { + "amphp/amp": "^2.3", + "doctrine/coding-standard": "^6.0", + "nyholm/psr7": "^1.2", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "0.12.82", + "phpstan/phpstan-phpunit": "0.12.18", + "phpstan/phpstan-strict-rules": "0.12.9", + "phpunit/phpunit": "^7.2 || ^8.5", + "psr/http-message": "^1.0", + "react/promise": "2.*", + "simpod/php-coveralls-mirror": "^3.0", + "squizlabs/php_codesniffer": "3.5.4" + }, + "suggest": { + "psr/http-message": "To use standard GraphQL server", + "react/promise": "To leverage async resolving on React PHP platform" + }, + "type": "library", + "autoload": { + "psr-4": { + "GraphQL\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP port of GraphQL reference implementation", + "homepage": "https://github.com/webonyx/graphql-php", + "keywords": [ + "api", + "graphql" + ], + "support": { + "issues": "https://github.com/webonyx/graphql-php/issues", + "source": "https://github.com/webonyx/graphql-php/tree/v14.11.5" + }, + "funding": [ + { + "url": "https://opencollective.com/webonyx-graphql-php", + "type": "open_collective" + } + ], + "time": "2022-01-24T11:13:31+00:00" } ], "packages-dev": [], @@ -679,5 +745,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.0.0" } diff --git a/js/customElements/blogFooter.js b/js/customElements/blogFooter.js index 526894c49adc635fba4004b83412b78faaf0de59..5be26eac8fc96f8965e90c596b06ba61cae492aa 100644 --- a/js/customElements/blogFooter.js +++ b/js/customElements/blogFooter.js @@ -1,31 +1,31 @@ class blogFooter extends HTMLElement { constructor(){ super(); - let xhr = new XMLHttpRequest(); - let ul = document.createElement("ul"); - xhr.onreadystatechange = () => { - if(xhr.readyState === 4) { - if (xhr.status === 200) { - let blog = JSON.parse(xhr.responseText); - blog.forEach((element) => { - let li = document.createElement("li"); - let a = document.createElement("a"); - a.href = "/post.html?id=" + element["id"]; - a.innerText = element["title"]; - li.appendChild(a); - ul.appendChild(li); - }); - this.appendChild(ul); - } else { - let p = document.createElement("p"); - p.innerText = "Leider konnte dieser Inhalt nicht geladen werden, bitte versuche die Seite neu zu laden oder komme später wieder zurück"; - this.appendChild(p); + this.getBlogEntries(); + } - } - } + async getBlogEntries() { + let ul = document.createElement("ul"); + this.appendChild(ul); + var graphql = JSON.stringify({ + query: 'query($count: Int!) { blogPosts(count: $count) { title id }}', + variables: { + "count": 5 } - xhr.open("GET", "/API/getBlogElements.php?position=footer"); - xhr.send(); + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let posts = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.blogPosts; + posts.forEach((element) => { + let li = document.createElement("li"); + let a = document.createElement("a"); + a.href = "/post.html?id=" + element["id"]; + a.innerText = element["title"]; + li.appendChild(a); + ul.appendChild(li); + }); } } diff --git a/js/customElements/blogIndex.js b/js/customElements/blogIndex.js index b356df7970ef4d14c85ed600928ae8cdac868df2..b3091b00495caed466437c481f72e87a4938e360 100644 --- a/js/customElements/blogIndex.js +++ b/js/customElements/blogIndex.js @@ -1,48 +1,48 @@ class BlogIndex extends HTMLElement { constructor() { super(); - let xhr = new XMLHttpRequest(); - xhr.onreadystatechange = () => { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - let blog = JSON.parse(xhr.responseText); - blog.forEach((element) => { - const article = document.createElement("article"); - article.classList.add("breakWord"); - this.appendChild(article); - - const h2 = document.createElement("h2"); - h2.innerText = element["title"]; - article.appendChild(h2); - - const content = document.createElement("p"); - content.classList.add("breakWord"); - content.innerHTML = element["content"]; - article.appendChild(content); - - const moreP = document.createElement("p"); - moreP.classList.add("center"); - article.appendChild(moreP); - - const moreLink = document.createElement("a"); - moreLink.href = "/post.html?id=" + element["id"]; - moreP.appendChild(moreLink); - - const moreButton = document.createElement("button"); - moreButton.innerText = "Mehr lesen"; - moreLink.appendChild(moreButton); - }); - - } else { - let p = document.createElement("p"); - p.innerText = "Leider konnte dieser Inhalt nicht geladen werden, bitte versuche die Seite neu zu laden oder komme später wieder zurück"; - this.appendChild(p); + this.getBlogPosts(); + } - } - } + async getBlogPosts() { + var graphql = JSON.stringify({ + query: 'query($count: Int! $contentLength: Int!) { blogPosts(count: $count contentLength: $contentLength) { content title id }}', + variables: { + "count": 3, + "contentLength": 300 } - xhr.open("GET", "/API/getBlogElements.php?position=index"); - xhr.send(); + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let posts = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.blogPosts; + posts.forEach((element) => { + const article = document.createElement("article"); + article.classList.add("breakWord"); + this.appendChild(article); + + const h2 = document.createElement("h2"); + h2.innerText = element["title"]; + article.appendChild(h2); + + const content = document.createElement("p"); + content.classList.add("breakWord"); + content.innerHTML = element["content"]; + article.appendChild(content); + + const moreP = document.createElement("p"); + moreP.classList.add("center"); + article.appendChild(moreP); + + const moreLink = document.createElement("a"); + moreLink.href = "/post.html?id=" + element["id"]; + moreP.appendChild(moreLink); + + const moreButton = document.createElement("button"); + moreButton.innerText = "Mehr lesen"; + moreLink.appendChild(moreButton); + }); } } diff --git a/js/customElements/commentsDisplay.js b/js/customElements/commentsDisplay.js index fb86044c742ba74f0564f867bfe7642093dae57d..48a2c5f1739ac052c49f881e1d239af4d44db02b 100644 --- a/js/customElements/commentsDisplay.js +++ b/js/customElements/commentsDisplay.js @@ -1,48 +1,46 @@ class commentsDisplay extends HTMLElement { constructor() { super(); - let path = window.location.pathname; - let pageName = path.split("/").pop(); - - let xhr = new XMLHttpRequest(); - xhr.onreadystatechange = () => { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - let comments = JSON.parse(xhr.responseText); - comments.forEach((element) => { - const h3 = document.createElement("h3"); - h3.classList.add("commentTitle"); - h3.innerText = element["name"]; - this.appendChild(h3); - - const commentDiv = document.createElement("div"); - commentDiv.classList.add("comment"); - this.appendChild(commentDiv); - - const image = document.createElement("img"); - image.src = element["gravatarURL"]; - commentDiv.appendChild(image); - - const article = document.createElement("article"); - article.classList.add("commentArticle"); - commentDiv.appendChild(article); - - const commentText = document.createElement("p"); - commentText.classList.add("commentText"); - commentText.innerText = element["comment"]; - article.appendChild(commentText); - - }); - } else { - let p = document.createElement("p"); - p.innerText = "Leider konnte dieser Inhalt nicht geladen werden, bitte versuche die Seite neu zu laden oder komme später wieder zurück."; - this.appendChild(p); + this.getComments() + } - } - } + async getComments() { + var graphql = JSON.stringify({ + query: 'query($article: String!) { comments(article: $article) { name comment gravatarURL }}', + variables: { + "article": window.location.pathname } - xhr.open("GET", "/API/projectComments.php?article=" + pageName); - xhr.send(); + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let comments = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.comments; + this.innerHTML = ""; + comments.forEach((element) => { + const h3 = document.createElement("h3"); + h3.classList.add("commentTitle"); + h3.innerText = element["name"]; + this.appendChild(h3); + + const commentDiv = document.createElement("div"); + commentDiv.classList.add("comment"); + this.appendChild(commentDiv); + + const image = document.createElement("img"); + image.src = element["gravatarURL"]; + commentDiv.appendChild(image); + + const article = document.createElement("article"); + article.classList.add("commentArticle"); + commentDiv.appendChild(article); + + const commentText = document.createElement("p"); + commentText.classList.add("commentText"); + commentText.innerText = element["comment"]; + article.appendChild(commentText); + + }); } } diff --git a/js/customElements/contactMailButton.js b/js/customElements/contactMailButton.js index 646110d8b2ad69bb1e9a397f6530f5bdafab839e..5d1aa176d7e9ca91b63289db5bd71bafacda980f 100644 --- a/js/customElements/contactMailButton.js +++ b/js/customElements/contactMailButton.js @@ -6,7 +6,15 @@ class contactMailButton extends HTMLElement { } async addButton() { - let sitekey = await (await fetch("/API/config.php?name=sitekey")).text(); + var graphql = JSON.stringify({ + query: "query {sitekey}" + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + + let sitekey = (await (await fetch("/API/graphql.php", requestOptions)).json()).data.sitekey; console.log(sitekey); this.innerHTML = `E-Mail: <button id="emailButton" class="h-captcha" data-sitekey="${sitekey}" data-callback="onSubmit">laden</button><br>`; const script = document.createElement("script"); diff --git a/js/customElements/ebkBanner.js b/js/customElements/ebkBanner.js index 6be307612863c023f2015a7843e96d93c9d760c9..9ff55f32438a20c6fbcd298fe86a0ba45f085d6e 100644 --- a/js/customElements/ebkBanner.js +++ b/js/customElements/ebkBanner.js @@ -1,20 +1,24 @@ class ebkBanner extends HTMLElement { constructor(){ super(); - let xhr = new XMLHttpRequest(); - xhr.onreadystatechange = () => { - if(xhr.readyState === 4 && xhr.status === 200){ - if(xhr.responseText > 0) { - const h2 = document.createElement("h2"); - h2.classList.add("red"); - h2.innerHTML = "Ich biete aktuell wieder verschiedene Artikel zum verkauf an, eine genaue Übersicht ist <a class=\"red\" href=\"/selling.html\">hier</a> zu sehen." - this.appendChild(h2); - } - } - } + this.generateBanner(); + } - xhr.open("GET", "/API/ebk.php?count"); - xhr.send(); + async generateBanner() { + var graphql = JSON.stringify({ + query: 'query { ebayKleinanzeigen{ count }}', + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let elementCount = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.ebayKleinanzeigen.count; + if(elementCount > 0) { + const h2 = document.createElement("h2"); + h2.classList.add("red"); + h2.innerHTML = "Ich biete aktuell wieder verschiedene Artikel zum verkauf an, eine genaue Übersicht ist <a class=\"red\" href=\"/selling.html\">hier</a> zu sehen." + this.appendChild(h2); + } } } diff --git a/js/customElements/newComment.js b/js/customElements/newComment.js index 1523128ddbd648cf1b4ce06e00d644dbc36e592e..4e8d9444e7405effc4294f9ed71d305bbafad26a 100644 --- a/js/customElements/newComment.js +++ b/js/customElements/newComment.js @@ -8,31 +8,127 @@ class newComment extends HTMLElement { } async setupForm() { - let sitekey = await (await fetch("/API/config.php?name=sitekey")).text(); + var graphql = JSON.stringify({ + query: "query {sitekey}" + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + + let sitekey = (await (await fetch("/API/graphql.php", requestOptions)).json()).data.sitekey; let script = document.createElement('script'); script.src = "https://hCaptcha.com/1/api.js"; script.type = 'text/javascript'; script.onload = () => { - let pageName = window.location.pathname.split("/").pop(); - this.parentElement.innerHTML = ` - <form action="/API/newComment.php" method="post"> - <label for="name">Name:</label><br> - <input type="text" id="name" name="name"><br><br> + let pageName = window.location.pathname + const parent = this.parentElement; + parent.innerHTML = ""; + + const form = document.createElement("form"); + parent.appendChild(form); + + const labelName = document.createElement("label") + labelName.setAttribute("for", "name"); + labelName.innerText = "Name:"; + form.appendChild(labelName); + + const nameInput = document.createElement("input"); + nameInput.type = "text"; + nameInput.name = "name"; + nameInput.id = "name"; + form.appendChild(nameInput); + + let linebreak = document.createElement("br"); + form.appendChild(linebreak); + + const labelMail = document.createElement("label") + labelMail.setAttribute("for", "email"); + labelMail.innerText = "E-Mail: (wird nicht veröffentlicht)"; + form.appendChild(labelMail); + + const mailInput = document.createElement("input"); + mailInput.type = "email"; + mailInput.name = "email"; + mailInput.id = "email"; + form.appendChild(mailInput); + + linebreak = document.createElement("br"); + form.appendChild(linebreak); + + const labelComment = document.createElement("label") + labelComment.setAttribute("for", "comment"); + labelComment.innerText = "Kommentar:"; + form.appendChild(labelComment); + + const commentInput = document.createElement("textarea"); + commentInput.name = "comment"; + commentInput.id = "comment"; + form.appendChild(commentInput); + - <label for="email">E-Mail: (wird nicht veröffentlicht)</label><br> - <input type="text" id="email" name="email"><br><br> + linebreak = document.createElement("br"); + form.appendChild(linebreak); + + const hcaptcha = document.createElement("div"); + hcaptcha.classList.add("h-captcha"); + hcaptcha.setAttribute("data-theme", "dark"); + hcaptcha.setAttribute("data-sitekey", sitekey); + form.appendChild(hcaptcha); - <label for="comment">Kommentar:</label><br> - <textarea name="comment" id="comment"></textarea><br><br> - - <div class="h-captcha" data-theme="dark" data-sitekey="${sitekey}"></div><br> - - <input type="hidden" name="pagename" id="pagename" value="${pageName}"> - <input type="submit" value="Kommentar veröffentlichen"><br> - <p>Mit dem Klick auf den obigen Button erklären sie sich mit der <a href="/datenschutzerklaerung.html">Datenschutzerklärung</a> einverstanden.</p> - </form> - `; + linebreak = document.createElement("br"); + form.appendChild(linebreak); + + const submitButton = document.createElement("input"); + submitButton.value = "Kommentar veröffentlichen"; + submitButton.type = "submit"; + form.appendChild(submitButton); + + const labelDatenschutz = document.createElement("p"); + labelDatenschutz.innerText = "Mit dem Klick auf den obigen Button erklären sie sich mit der "; + form.appendChild(labelDatenschutz); + + const datenschutzLink = document.createElement("a"); + datenschutzLink.innerText = "Datenschutzerklärung"; + datenschutzLink.href = "/datenschutzerklaerung.html"; + labelDatenschutz.appendChild(datenschutzLink); + + const datenschutzTextNode = document.createTextNode(" einverstanden"); + labelDatenschutz.appendChild(datenschutzTextNode); + + submitButton.onclick = async () => { + if(nameInput.value == "" || commentInput.value == "") { + alert("Name oder Kommentar nicht ausgefüllt."); + return; + } + + var graphql = JSON.stringify({ + query: 'query($article: String!, $name: String!, $hCaptchaResponse: String!, $email: String!, $comment: String!) { newComment(article: $article, name: $name, email: $email, comment: $comment, hCaptchaResponse: $hCaptchaResponse)}', + variables: { + "article": pageName, + "name": nameInput.value, + "email": mailInput.value, + "comment": commentInput.value, + "hCaptchaResponse": form.querySelector(".h-captcha iframe").getAttribute("data-hcaptcha-response") + } + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let data = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data; + if(data.newComment == "OK"){ + document.querySelector("jl-comments_display").getComments(); + parent.innerHTML = "<jl-new_comment></jl-new_comment>" + } else { + alert("Fehler: " + data.newComment); + } + } + + form.onsubmit = () => { + return false; + } } document.body.append(script); } diff --git a/js/customElements/sellingTable.js b/js/customElements/sellingTable.js index cf88d68a1471e10e89282c421c530e8d4f9f85c4..53bb82da5e084cbab7914d1a242f3dd6581ea855 100644 --- a/js/customElements/sellingTable.js +++ b/js/customElements/sellingTable.js @@ -1,13 +1,17 @@ import * as basicLightbox from 'basiclightbox' class sellingTable extends HTMLElement { - constructor(){ - const config = [ + + constructor() { + super(); + + this.config = [ { "title": "Bild", - "fieldName": "previewImage", + "fieldName": "preview", "displayType": "image", - "fullImage": "image" + "fullImage": "image", + "index": 0 }, { "title": "Titel", @@ -31,68 +35,70 @@ class sellingTable extends HTMLElement { "linkText": "Anzeige ansehen", "target": "_blank" }, - ] + ]; - super(); + this.generateTable(); + } + + async generateTable() { const table = document.createElement("table"); this.appendChild(table); const tr = document.createElement("tr"); table.appendChild(tr); - config.forEach(element => { + this.config.forEach(element => { const th = document.createElement("th"); th.innerText = element["title"]; tr.appendChild(th); }); - let xhr = new XMLHttpRequest(); - xhr.onreadystatechange = () => { - if(xhr.readyState === 4 && xhr.status === 200){ - const response = JSON.parse(xhr.responseText); - response.forEach( ad => { - const tr = document.createElement("tr"); - table.appendChild(tr); - config.forEach(element => { - const th = document.createElement("th"); + var graphql = JSON.stringify({ + query: 'query { ebayKleinanzeigen(imageCount: 1) { elements { images { preview image } title price shipping link }}}', + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let elements = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.ebayKleinanzeigen.elements; + elements.forEach(ad => { + const tr = document.createElement("tr"); + table.appendChild(tr); + this.config.forEach(element => { + const th = document.createElement("th"); - switch(element["displayType"]) { - case "text": - th.innerText = ad[element["fieldName"]]; - break; - case "link": - const link = document.createElement("a"); - th.appendChild(link); - link.href = ad[element["fieldName"]]; - link.innerText = element["linkText"]; - - if("target" in element) { - link.target = element["target"]; - } - break; - case "image": - const img = document.createElement("img"); - th.appendChild(img); - img.src = ad[element["fieldName"]]; - img.onclick = () => { - const instance = basicLightbox.create(` - <img src="${ad[element["fullImage"]]}"> - `); - instance.show(); - } - break; + switch (element["displayType"]) { + case "text": + th.innerText = ad[element["fieldName"]]; + break; + case "link": + const link = document.createElement("a"); + th.appendChild(link); + link.href = ad[element["fieldName"]]; + link.innerText = element["linkText"]; + if ("target" in element) { + link.target = element["target"]; + } + break; + case "image": + const img = document.createElement("img"); + th.appendChild(img); + img.src = ad["images"][element["index"]][element["fieldName"]]; + img.onclick = () => { + const instance = basicLightbox.create(` + <img src="${ad["images"][element["index"]][element["fullImage"]]}"> + `); + instance.show(); } + break; - tr.appendChild(th); - }); - - }) - } - } + } - xhr.open("GET", "/API/ebk.php"); - xhr.send(); + tr.appendChild(th); + }); + + }); } } diff --git a/js/customElements/skills.js b/js/customElements/skills.js index 65561b928c4e0343bba68c4dab54ccc1cd0f8939..c37631b016f7d8cb658b51f096baf9776440d327 100644 --- a/js/customElements/skills.js +++ b/js/customElements/skills.js @@ -1,19 +1,26 @@ class Skill extends HTMLElement { constructor() { super(); - let xhr = new XMLHttpRequest(); - xhr.onreadystatechange = () => { - if (xhr.readyState == 4 && xhr.status == 200) { - JSON.parse(xhr.responseText).forEach(skill => { - const image = document.createElement("img"); - image.classList.add("skills"); - image.src = "/API/getFile.php?filename=" + skill; - this.appendChild(image); - }); - } - } - xhr.open("GET", "/API/skills.php"); - xhr.send(); + this.getSkills(); + } + + async getSkills(){ + var graphql = JSON.stringify({ + query: "query {skills}" + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + + let skills = (await (await fetch("/API/graphql.php", requestOptions)).json()).data.skills; + skills.forEach(skill => { + const image = document.createElement("img"); + image.classList.add("skills"); + image.src = "/API/getFile.php?filename=" + skill; + this.appendChild(image); + }); + } } diff --git a/js/viewPost.js b/js/viewPost.js index 01241e908784e33d2907bf31be386a0f8cda6ecf..c7e3d63d778457ac1d048e2668fc5d9ddf94197b 100644 --- a/js/viewPost.js +++ b/js/viewPost.js @@ -26,7 +26,17 @@ async function loadPost() { if(id == null) { content.innerHTML = "<h1>404 - Post not found</h1>"; } else { - let post = await (await fetch("/API/getPost.php?id=" + id)).json(); + var graphql = JSON.stringify({ + query: 'query($postID: String!) {blogPost(id: $postID) {content title}}', + variables: { + "postID": id + } + }) + var requestOptions = { + method: 'POST', + body: graphql, + }; + let post = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.blogPost; content.innerHTML = post["content"]; document.title = post["title"] + " - Jonas Leder"; diff --git a/package.json b/package.json index 8fa718de2c45ce4fd8483bdc1c7d9ef18a08787a..53805d5b6bb32108561e733377f6a53e7f4b03d5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "author": "jonasled <git@jonasled.de>", "license": "GPL-3.0-or-later", "scripts": { - "compile": "concurrently \"yarn css\" \"yarn js\"", + "build": "concurrently \"yarn css\" \"yarn js\"", "css": "stylus styl/ -o public/css/ ", "js": "webpack --config ./webpack.conf.js", "watch": "concurrently \"stylus -w styl/ -o public/css/\" \"cd public && php -S 0.0.0.0:1234\" \"webpack --config ./webpack.conf.js --mode development --watch\"" diff --git a/public/API/config.php b/public/API/config.php deleted file mode 100644 index 336fdbd8d55bfecd9718ba2aedb017eb4cfcee07..0000000000000000000000000000000000000000 --- a/public/API/config.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -require "./lib/config.php"; - -$configValue = $_GET['name']; - -switch ($configValue){ - case "sitekey": - echo($sitekey); - break; - default: - echo("notFound"); -} diff --git a/public/API/ebk.php b/public/API/ebk.php deleted file mode 100644 index 29541c1e17e824e809ede226252a95a8369ae9ea..0000000000000000000000000000000000000000 --- a/public/API/ebk.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php -require 'vendor/autoload.php'; -require "./lib/config.php"; - -use GuzzleHttp\Client; - -$responseJSON = []; - -$client = new Client(); -$headers = [ - 'authorization' => 'Basic ' . $ebayKleinanzeigenToken, - 'user-agent' => 'okhttp/4.9.1', - 'x-ebayk-app' => '4e10d7fd-6fef-4f87-afb0-b8ede2f494071636475109828', - 'Host' => 'api.ebay-kleinanzeigen.de', - 'Accept' => '*/*', - 'Accept-Encoding' => 'gzip, deflate, br' -]; -$response = $client->request('GET', "https://api.ebay-kleinanzeigen.de/api/ads.json?_in=title,price,pictures,link,features-active,search-distance,negotiation-enabled,attributes,medias,medias.media,medias.media.title,medias.media.media-link,store-id,store-title&page=0&size=31&userIds=$ebayKleinanzeigenUserId&pictureRequired=false&includeTopAds=false&limitTotalResultCount=true", [ - 'headers' => $headers ]); - -$response = json_decode($response->getBody(), true); -$ads = $response["{http://www.ebayclassifiedsgroup.com/schema/ad/v1}ads"]["value"]["ad"]; - -foreach($ads as $ad) { - $element = [ - "title" => $ad["title"]["value"], - "price" => $ad["price"]["amount"]["value"] . " €", - "shipping" => "nein" - ]; - - foreach($ad["attributes"]["attribute"] as $attribute) { - if(str_contains($attribute["name"], "versand")) { - $element["shipping"] = $attribute["value"][0]["value"]; - } - } - - foreach($ad["link"] as $link) { - if($link["rel"] == "self-public-website") { - $element["link"] = $link["href"]; - } - } - - if(sizeof($ad["pictures"]["picture"]) > 0) { - foreach($ad["pictures"]["picture"][0]["link"] as $picture) { - if($picture["rel"] == "teaser") { - $element["previewImage"] = str_replace("https://i.ebayimg.com", "/API/ebayimg.php?url=", $picture["href"]); - } - if($picture["rel"] == "XXL") { - - $element["image"] = str_replace("https://i.ebayimg.com", "/API/ebayimg.php?url=", $picture["href"]); - } - } - } - - array_push($responseJSON, $element); -} - -if(isset($_GET["count"])) { - echo sizeof($responseJSON); - die(); -} -echo json_encode($responseJSON); \ No newline at end of file diff --git a/public/API/getBlogElements.php b/public/API/getBlogElements.php deleted file mode 100644 index 8271e20e55a8135c3570d2c82ad006d22d0567ca..0000000000000000000000000000000000000000 --- a/public/API/getBlogElements.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php -include "./lib/config.php"; -include "./lib/mysql.php"; - -$position = $_GET['position']; - -if($position == "index"){ - $limit = $homeMaxPost; -} else if($position == "footer"){ - $limit = $footerMaxPost; -} else { - die("wrong parameter"); -} -$responseJSON = []; - -$result = $conn->query("SELECT * FROM posts order by id desc limit $limit"); -if ($result->num_rows > 0) { - while ($row = $result->fetch_assoc()) { - $blogElement = [ - "title" => $row["title"], - "id" => $row["id"], - "content" => $row["content"] - ]; - - array_push($responseJSON, $blogElement); - } -} -header('Content-Type: application/json'); -echo json_encode($responseJSON); \ No newline at end of file diff --git a/public/API/getMail.php b/public/API/getMail.php deleted file mode 100644 index b2f438b113e2f7f78d036114fd6212d49096c500..0000000000000000000000000000000000000000 --- a/public/API/getMail.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php -include("./lib/config.php"); - -require("./vendor/autoload.php"); -use GuzzleHttp\Client; - -$data = array( - 'secret' => $secretkey, - 'response' => $_POST['h-captcha-response'] -); -$client = new Client(); - -$response = $client->post("https://hcaptcha.com/siteverify", [ - "form_params" => $data -]); - -$responseData = json_decode($response->getBody()); -if($responseData->success) { - echo("$contactmail"); -} else { - echo("Failed to verify Captcha"); -} \ No newline at end of file diff --git a/public/API/getPost.php b/public/API/getPost.php deleted file mode 100644 index 9ac86e89b3919c1e679beba9d301f7632810095c..0000000000000000000000000000000000000000 --- a/public/API/getPost.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -include "./lib/config.php"; -include "./lib/mysql.php"; - -$id = $conn->real_escape_string($_GET["id"]); -$result = $conn->query("SELECT * FROM posts WHERE id=$id"); -if ($result->num_rows > 0) { - $row = $result->fetch_assoc(); -} else { - die("Post not found"); -} - -$title = $row["title"]; -$content = $row["content"]; -$date = $row["date"]; -$id = $row["id"]; - -header('Content-Type: application/json'); -echo json_encode([ - "title" => $title, - "content" => $content, - "date" => $date, - "id" => $id -]); \ No newline at end of file diff --git a/public/API/graphql.php b/public/API/graphql.php new file mode 100644 index 0000000000000000000000000000000000000000..cec07bc38dea6dcc516d20c86c8fb583fffa00b3 --- /dev/null +++ b/public/API/graphql.php @@ -0,0 +1,35 @@ +<?php +use GraphQL\GraphQL; +use GraphQL\Type\Schema; + +require 'vendor/autoload.php'; +require "./lib/config.php"; +require "./lib/mysql.php"; +require "./queries/queries.php"; + +$schema = new Schema([ + 'query' => $queryType +]); + +$rawInput = file_get_contents('php://input'); +$input = json_decode($rawInput, true); +$query = $input['query']; +$variableValues = isset($input['variables']) ? $input['variables'] : null; + +try { + $rootValue = [ + "db"=> $conn + ]; + $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); + $output = $result->toArray(); +} catch (\Exception $e) { + $output = [ + 'errors' => [ + [ + 'message' => $e->getMessage() + ] + ] + ]; +} +header('Content-Type: application/json'); +echo json_encode($output); \ No newline at end of file diff --git a/public/API/newComment.php b/public/API/newComment.php deleted file mode 100644 index ab8d29800c3352b30c90f4d5c9da5b87e42a4320..0000000000000000000000000000000000000000 --- a/public/API/newComment.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php -require './vendor/autoload.php'; -include("./lib/config.php"); -include("./lib/mysql.php"); - -use GuzzleHttp\Client; - -$data = array( - 'secret' => $secretkey, - 'response' => $_POST['h-captcha-response'] -); - -$client = new Client(); - -$response = $client->post("https://hcaptcha.com/siteverify", [ - "form_params" => $data -]); - -$responseData = json_decode($response->getBody()); - - - -if($responseData->success) { - - $article =$conn->escape_string($_POST["pagename"]); - $name = $conn->escape_string($_POST["name"]); - $email = $conn->escape_string($_POST["email"]); - $comment = $conn->escape_string($_POST["comment"]); - - $sql = "INSERT INTO comments (name, email, comment, article) VALUES ('$name', '$email', '$comment', '$article')"; - - if ($conn->query($sql) === TRUE) { - header("Location: " . $_SERVER["HTTP_REFERER"]); - } else { - echo "Error: " . $sql . "<br>" . $conn->error; - } -} else { - echo "Failed to verify captcha."; -} diff --git a/public/API/projectComments.php b/public/API/projectComments.php deleted file mode 100644 index e39b3fe9ea3a2ba8d73822f313c1b1f869ca73d3..0000000000000000000000000000000000000000 --- a/public/API/projectComments.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -include "./lib/config.php"; -include "./lib/mysql.php"; -include "./lib/getGravatar.php"; - -$article = $conn->real_escape_string($_GET["article"]); - -$responseJSON = []; - -$result = $conn->query("SELECT * FROM comments WHERE article='$article'"); -if ($result->num_rows > 0) { - while ($row = $result->fetch_assoc()) { - $commentElement = [ - "name" => $row["name"], - "comment" => $row["comment"], - "gravatarURL" => get_gravatar($row["email"]) - ]; - - array_push($responseJSON, $commentElement); - } -} -header('Content-Type: application/json'); -echo json_encode($responseJSON); \ No newline at end of file diff --git a/public/API/queries/blogPost.php b/public/API/queries/blogPost.php new file mode 100644 index 0000000000000000000000000000000000000000..6f3d732706defa0f7675c2050c76e4c97e0145e5 --- /dev/null +++ b/public/API/queries/blogPost.php @@ -0,0 +1,65 @@ +<?php + +use GraphQL\Type\Definition\Type; +use GraphQL\Type\Definition\ObjectType; + +$blogPostFields = new ObjectType([ + "name" => "Blog", + "fields" => [ + "title" => Type::string(), + "content" => Type::string(), + "date" => Type::string(), + "id" => Type::string() + ], +]); + +function blogPost($id, $conn) +{ + $id = $conn->real_escape_string($id); + $result = $conn->query("SELECT * FROM posts WHERE id=$id"); + if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + } else { + return [ + "title" => "Nicht Gefunden", + "content" => "Post wurde nicht gefunden", + "date" => "2000-01-01 00:00:00", + "id" => "-1" + ]; + } + + return [ + "title" => $row["title"], + "content" => $row["content"], + "date" => $row["date"], + "id" => $row["id"], + ]; +} + +function blogPosts($count, $contentLength, $conn) +{ + $response = []; + $result = $conn->query("SELECT * FROM posts order by id desc limit $count"); + if ($result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $content = $row["content"]; + if($contentLength != null && strlen($content) > $contentLength) { + $contentNew = substr($content, 0, $contentLength); + $contentRest = substr($content, $contentLength); + + $content = $contentNew . explode(" ", $contentRest)[0] . " ..."; + + } + $blogElement = [ + "title" => $row["title"], + "content" => $content, + "date" => $row["date"], + "id" => $row["id"], + ]; + + array_push($response, $blogElement); + } + } + + return $response; +} \ No newline at end of file diff --git a/public/API/queries/comments.php b/public/API/queries/comments.php new file mode 100644 index 0000000000000000000000000000000000000000..3b3d46ba952ab523e35140ffd1299ea0ee1c54dd --- /dev/null +++ b/public/API/queries/comments.php @@ -0,0 +1,65 @@ +<?php + +use GraphQL\Type\Definition\Type; +use GraphQL\Type\Definition\ObjectType; +use GuzzleHttp\Client; + +include "lib/getGravatar.php"; +$commentField = new ObjectType([ + "name" => "Comment", + "fields" => [ + "name" => Type::string(), + "comment" => Type::string(), + "gravatarURL" => Type::string(), + "id" => Type::int() + ], +]); + +function comments($article, $conn) +{ + $response = []; + $result = $conn->query("SELECT * FROM comments WHERE article='$article'"); + while ($row = $result->fetch_assoc()) { + $commentElement = [ + "name" => $row["name"], + "comment" => $row["comment"], + "gravatarURL" => get_gravatar($row["email"]), + "id" => $row["id"] + ]; + + array_push($response, $commentElement); + } + return $response; +} + +function newComment($conn, $article, $name, $email, $comment, $hCaptchaResponse) +{ + require "./lib/config.php"; + $data = array( + 'secret' => $secretkey, + 'response' => $hCaptchaResponse + ); + $client = new Client(); + + $response = $client->post("https://hcaptcha.com/siteverify", [ + "form_params" => $data + ]); + + $responseData = json_decode($response->getBody()); + if (!$responseData->success) { + return "Failed to verify Captcha"; + } + + $article = $conn->escape_string($article); + $name = $conn->escape_string($name); + $email = $conn->escape_string($email); + $comment = $conn->escape_string($comment); + + $sql = "INSERT INTO comments (name, email, comment, article) VALUES ('$name', '$email', '$comment', '$article')"; + + if ($conn->query($sql) === TRUE) { + return "OK"; + } else { + return "Error: " . $sql . "<br>" . $conn->error; + } +} diff --git a/public/API/queries/ebayKleinanzeigen.php b/public/API/queries/ebayKleinanzeigen.php new file mode 100644 index 0000000000000000000000000000000000000000..a479dec181fd9dc35abcf7fd9a9f749c890635d1 --- /dev/null +++ b/public/API/queries/ebayKleinanzeigen.php @@ -0,0 +1,103 @@ +<?php + +use GraphQL\Type\Definition\Type; +use GraphQL\Type\Definition\ObjectType; +use GuzzleHttp\Client; + +$ebayKleinanzeigenImages = new ObjectType([ + "name" => "EBK Image", + "fields" => [ + "preview" => Type::string(), + "image" => Type::string() + ] +]); + +$ebayKleinanzeigenElements = new ObjectType([ + "name" => "EBK Elements", + "fields" => [ + "title" => Type::string(), + "price" => Type::string(), + "shipping" => Type::string(), + "link" => Type::string(), + "images" => [ + "type" => Type::listOf($ebayKleinanzeigenImages), + "args" => [ + "count" => Type::int() + ] + ], + "id" => Type::string() + ] +]); + +$ebayKleinanzeigenFields = new ObjectType([ + "name" => "Ebay Kleinanzeigen", + "fields" => [ + "count" => Type::int(), + "elements" => Type::listOf($ebayKleinanzeigenElements) + ], +]); + +function ebayKleinanzeigen($imageCount) { + require "./lib/config.php"; + $elements = []; + + $client = new Client(); + $headers = [ + 'authorization' => 'Basic ' . $ebayKleinanzeigenToken, + 'user-agent' => 'okhttp/4.9.1', + 'x-ebayk-app' => '4e10d7fd-6fef-4f87-afb0-b8ede2f494071636475109828', + 'Host' => 'api.ebay-kleinanzeigen.de', + 'Accept' => '*/*', + 'Accept-Encoding' => 'gzip, deflate, br' + ]; + $response = $client->request('GET', "https://api.ebay-kleinanzeigen.de/api/ads.json?_in=title,price,pictures,link,features-active,search-distance,negotiation-enabled,attributes,medias,medias.media,medias.media.title,medias.media.media-link,store-id,store-title&page=0&size=31&userIds=$ebayKleinanzeigenUserId&pictureRequired=false&includeTopAds=false&limitTotalResultCount=true", [ + 'headers' => $headers ]); + + $response = json_decode($response->getBody(), true); + $ads = $response["{http://www.ebayclassifiedsgroup.com/schema/ad/v1}ads"]["value"]["ad"]; + + foreach($ads as $ad) { + $element = [ + "title" => html_entity_decode($ad["title"]["value"]), + "id" => $ad["id"], + "price" => $ad["price"]["amount"]["value"] . " €", + "shipping" => "nein" + ]; + + foreach($ad["attributes"]["attribute"] as $attribute) { + if(str_contains($attribute["name"], "versand")) { + $element["shipping"] = $attribute["value"][0]["value"]; + } + } + + foreach($ad["link"] as $link) { + if($link["rel"] == "self-public-website") { + $element["link"] = $link["href"]; + } + } + + $images = []; + foreach(array_slice($ad["pictures"]["picture"], 0, $imageCount) as $picture) { + $image = []; + + foreach($picture["link"] as $pictureSize) { + if($pictureSize["rel"] == "teaser") { + $image["preview"] = str_replace("https://i.ebayimg.com", "/API/ebayimg.php?url=", $pictureSize["href"]); + } + if($pictureSize["rel"] == "XXL") { + + $image["image"] = str_replace("https://i.ebayimg.com", "/API/ebayimg.php?url=", $pictureSize["href"]); + } + } + array_push($images, $image); + } + $element["images"] = $images; + + array_push($elements, $element); + } + + return [ + "count" => sizeof($elements), + "elements" => $elements + ]; +} \ No newline at end of file diff --git a/public/API/queries/mailAddress.php b/public/API/queries/mailAddress.php new file mode 100644 index 0000000000000000000000000000000000000000..17807df99aa67375d4c8012a2cb21bddc7d99802 --- /dev/null +++ b/public/API/queries/mailAddress.php @@ -0,0 +1,22 @@ +<?php +use GuzzleHttp\Client; + +function mailAddress($hCaptchaResponse) { + require "./lib/config.php"; + $data = array( + 'secret' => $secretkey, + 'response' => $hCaptchaResponse + ); + $client = new Client(); + + $response = $client->post("https://hcaptcha.com/siteverify", [ + "form_params" => $data + ]); + + $responseData = json_decode($response->getBody()); + if($responseData->success) { + return "$contactmail"; + } else { + return "Failed to verify Captcha"; + } +} \ No newline at end of file diff --git a/public/API/queries/queries.php b/public/API/queries/queries.php new file mode 100644 index 0000000000000000000000000000000000000000..bbd802a299751516ad1a5bdee50aaf2e55948962 --- /dev/null +++ b/public/API/queries/queries.php @@ -0,0 +1,79 @@ +<?php +use GraphQL\Type\Definition\ObjectType; +use GraphQL\Type\Definition\Type; + +require "./queries/skills.php"; +require "./queries/blogPost.php"; +require "./queries/comments.php"; +require "./queries/mailAddress.php"; +require "./queries/ebayKleinanzeigen.php"; + + +$queryType = new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'sitekey' => [ + 'type' => Type::string(), + 'resolve' => fn ($rootValue, $args) => $sitekey, + ], + 'mailAddress' => [ + 'type' => Type::string(), + "args" => [ + "hCaptchaResponse" => Type::string() + ], + 'resolve' => fn ($rootValue, $args) => mailAddress($args["hCaptchaResponse"]), + ], + 'skills' => [ + 'type' => Type::listOf(Type::string()), + 'resolve' => fn ($rootValue, $args) => getSkills(), + ], + 'blogPost' => [ + "type" => $blogPostFields, + 'args' => [ + 'id' => Type::nonNull(Type::string()), + ], + 'resolve' => fn ($rootValue, $args) => blogPost($args["id"], $rootValue["db"]), + ], + 'blogPosts' => [ + "type" => Type::listOf($blogPostFields), + "args" => [ + "count" => Type::nonNull(Type::int()), + "contentLength" => [ + "type" => Type::int(), + "defaultValue" => null + ] + + ], + 'resolve' => fn ($rootValue, $args) => blogPosts($args["count"], $args["contentLength"], $rootValue["db"]), + ], + 'comments' => [ + "type" => Type::listOf($commentField), + "args" => [ + "article" => Type::nonNull(Type::string()), + ], + 'resolve' => fn ($rootValue, $args) => comments($args["article"], $rootValue["db"]), + ], + "newComment" => [ + "type" => Type::string(), + "args" => [ + "article" => Type::string(), + "name" => Type::string(), + "email" => Type::string(), + "comment" => Type::string(), + "hCaptchaResponse" => Type::string() + ], + 'resolve' => fn ($rootValue, $args) => newComment($rootValue["db"], $args["article"], $args["name"], $args["email"], $args["comment"], $args["hCaptchaResponse"]), + ], + 'ebayKleinanzeigen' => [ + "type" => $ebayKleinanzeigenFields, + "args" => [ + "imageCount" => [ + "type" => Type::int(), + "defaultValue" => 0 + ] + ], + 'resolve' => fn ($rootValue, $args) => ebayKleinanzeigen($args["imageCount"]), + ] + + ], +]); diff --git a/public/API/queries/skills.php b/public/API/queries/skills.php new file mode 100644 index 0000000000000000000000000000000000000000..31670650e1ff02c573b4c61eceaddea7f976061d --- /dev/null +++ b/public/API/queries/skills.php @@ -0,0 +1,23 @@ +<?php + +function getSkills() { + require "./lib/config.php"; + $s3Client = new Aws\S3\S3Client([ + 'version' => 'latest', + 'region' => 'us-east-1', + 'endpoint' => $S3Server, + 'use_path_style_endpoint' => true, + 'credentials' => [ + 'key' => $S3AccessKey, + 'secret' => $S3SecretKey, + ], + ]); + + $result = $s3Client->ListObjects(['Bucket' => $S3BucketName, 'Delimiter'=>'/', 'Prefix' => 'skills/']); + + $response = []; + foreach ($result["Contents"] as $skill){ + array_push($response, $skill["Key"]); + } + return $response; +} \ No newline at end of file diff --git a/public/API/skills.php b/public/API/skills.php deleted file mode 100644 index 28116e71d41379b6cb73a03a7f102e9e74d63d99..0000000000000000000000000000000000000000 --- a/public/API/skills.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -include("./lib/config.php"); -require 'vendor/autoload.php'; - -$s3Client = new Aws\S3\S3Client([ - 'version' => 'latest', - 'region' => 'us-east-1', - 'endpoint' => $S3Server, - 'use_path_style_endpoint' => true, - 'credentials' => [ - 'key' => $S3AccessKey, - 'secret' => $S3SecretKey, - ], -]); - -$result = $s3Client->ListObjects(['Bucket' => $S3BucketName, 'Delimiter'=>'/', 'Prefix' => 'skills/']); - -$response = []; -foreach ($result["Contents"] as $skill){ - array_push($response, $skill["Key"]); -} - -header("Content-Type: application/json"); -echo json_encode($response); \ No newline at end of file diff --git a/public/impressum.html b/public/impressum.html index 92ca021d5381c9f87c8817fc116cf00f6a6ea16b..55ec96f6fb92889d2abd8e4fefcef34bae6df3a5 100644 --- a/public/impressum.html +++ b/public/impressum.html @@ -49,20 +49,24 @@ <a href="https://hcaptcha.com/privacy">Privacy Policy</a> and <a href="https://hcaptcha.com/terms">Terms of Service</a> apply. <script type="text/javascript"> - function onSubmit(token) { - let xmlhttp = new XMLHttpRequest(); - xmlhttp.onreadystatechange = function() { - if (this.readyState == 4 && this.status == 200) { - let button = document.getElementById("emailButton"); - let emailElement = document.createElement("p"); - emailElement.className = "emailBox"; - emailElement.innerText = this.responseText; - button.parentNode.replaceChild(emailElement, button); - } + async function onSubmit(token) { + var graphql = JSON.stringify({ + query: 'query($hCaptchaResponse: String!) { mailAddress(hCaptchaResponse: $hCaptchaResponse)}', + variables: { + "hCaptchaResponse": token + } + }) + var requestOptions = { + method: 'POST', + body: graphql, }; - xmlhttp.open("POST", "/API/getMail.php", true); - xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); - xmlhttp.send("h-captcha-response=" + token); + let mailAddress = (await (await fetch("http://localhost:1234/API/graphql.php", requestOptions)).json()).data.mailAddress; + + let button = document.getElementById("emailButton"); + let emailElement = document.createElement("p"); + emailElement.className = "emailBox"; + emailElement.innerText = mailAddress; + button.parentNode.replaceChild(emailElement, button); } </script> </div>