diff --git a/_i18n/messages.properties b/_i18n/messages.properties
index 37ffeec..0eb7723 100644
--- a/_i18n/messages.properties
+++ b/_i18n/messages.properties
@@ -10,4 +10,5 @@ Toolbar3=Edit and Download Final Image
Upload=Enhance Your Picture
placeholder=Choose File for Upload...
gui.loading=Processing Picture
-gui.loadingLong=Please wait ...Processing Picture
\ No newline at end of file
+gui.loadingLong=Please wait ...Processing Picture
+btnGHImport=Import From Github
\ No newline at end of file
diff --git a/app/profilePic/profilePic/controller/App.controller.js b/app/profilePic/profilePic/controller/App.controller.js
index cb03e21..5570ed0 100644
--- a/app/profilePic/profilePic/controller/App.controller.js
+++ b/app/profilePic/profilePic/controller/App.controller.js
@@ -1,98 +1,180 @@
/* eslint-disable no-undef */
/*eslint-env es6 */
"use strict";
-sap.ui.define([
+sap.ui.define(
+ [
"profilePic/controller/BaseController",
"sap/m/MessageToast",
"sap/ui/core/Core",
"sap/ui/model/json/JSONModel",
"sap/ui/Device",
- "sap/suite/ui/commons/library"
-],
- function (BaseController, MessageToast, oCore, JSONModel, Device, SuiteLibrary) {
+ "sap/suite/ui/commons/library",
+ "sap/m/Dialog",
+ ],
+ function (
+ BaseController,
+ MessageToast,
+ oCore,
+ JSONModel,
+ Device,
+ SuiteLibrary,
+ Dialog
+ ) {
+ return BaseController.extend("profilePic.controller.App", {
+ onInit: function () {
+ var oImageEditor = this.getView().byId("image"),
+ oModel = new JSONModel({
+ blocked: true,
+ username: "",
+ ghRateLimit: {},
+ });
- return BaseController.extend("profilePic.controller.App", {
- onInit: function () {
- var oImageEditor = this.getView().byId("image"),
- oModel = new JSONModel({
- blocked: true
- })
+ this.getView().setModel(oModel);
+ if (!Device.browser.msie) {
+ // svg files are not supported in Internet Explorer
+ oImageEditor.setCustomShapeSrc(
+ sap.ui.require.toUrl("sap/suite/ui/commons/statusindicator") +
+ "/shapes/bulb.svg"
+ );
+ }
+ },
- this.getView().setModel(oModel)
- if (!Device.browser.msie) {
- // svg files are not supported in Internet Explorer
- oImageEditor.setCustomShapeSrc(sap.ui.require.toUrl("sap/suite/ui/commons/statusindicator") + "/shapes/bulb.svg")
- }
- },
-
- uploadPressed: async function (oEvent) {
- let view = this.getView()
- let controller = view.getController()
- let oFileUploader = view.byId("fileToUpload")
- if (!oFileUploader.getValue()) {
- MessageToast.show("Choose a file first")
- return
- }
- let param = view.byId("uploadParam")
- //param.setValue(oInput.getActivePage())
- oFileUploader.getParameters()
- var oImageEditor = this.getView().byId("image")
- oImageEditor.applyVisibleCrop()
- console.log(oImageEditor.getMode())
- oFileUploader.getProcessedBlobsFromArray = async function (oBlobs) {
- return new Promise(async (resolve, reject) => {
- let newBlob = await oImageEditor.getImageAsBlob()
- resolve([newBlob])
- })
- }
- controller.startBusy()
- oFileUploader.upload(true)
- },
-
- uploadStart: async function (oEvent) {
- let view = this.getView()
- let controller = view.getController()
- controller.startBusy()
- },
+ uploadPressed: async function (oEvent) {
+ let view = this.getView();
+ let controller = view.getController();
+ let oFileUploader = view.byId("fileToUpload");
+ if (!oFileUploader.getValue()) {
+ MessageToast.show("Choose a file first");
+ return;
+ }
+ let param = view.byId("uploadParam");
+ //param.setValue(oInput.getActivePage())
+ oFileUploader.getParameters();
+ var oImageEditor = this.getView().byId("image");
+ oImageEditor.applyVisibleCrop();
+ oFileUploader.getProcessedBlobsFromArray = async function (oBlobs) {
+ return new Promise(async (resolve, reject) => {
+ let newBlob = await oImageEditor.getImageAsBlob();
+ resolve([newBlob]);
+ });
+ };
+ controller.startBusy();
+ oFileUploader.upload(true);
+ },
- uploadComplete: async function (oEvent) {
- let view = this.getView()
- let controller = view.getController()
- let dataURL = "data:image/png;base64," + oEvent.getParameters().responseRaw
- let oImageEditor = view.byId("image")
- await oImageEditor.setSrc(dataURL)
- controller.endBusy(controller)
- },
+ uploadStart: async function (oEvent) {
+ let view = this.getView();
+ let controller = view.getController();
+ controller.startBusy();
+ },
- onSaveAsPress: async function () {
- let view = this.getView()
- let controller = view.getController()
- let oImageEditor = view.byId("image")
- oImageEditor.openSaveDialog()
- controller.openUrl('https://people.sap.com/', true)
+ uploadComplete: async function (oEvent) {
+ let view = this.getView();
+ let controller = view.getController();
+ let dataURL =
+ "data:image/png;base64," + oEvent.getParameters().responseRaw;
+ let oImageEditor = view.byId("image");
+ await oImageEditor.setSrc(dataURL);
+ controller.endBusy(controller);
+ },
- },
- onImageLoaded: async function (oEvent) {
- let view = this.getView()
- let oImageEditor = view.byId("image")
- oImageEditor.zoomToFit()
- oImageEditor.setCropAreaByRatio(1, 1)
- oImageEditor.setMode(SuiteLibrary.ImageEditorMode.CropEllipse)
- console.log(oImageEditor.getMode())
-
-
-
- },
- onFileChange: async function (oEvent) {
- var oFile = oEvent.getParameter("files")[0],
- oImageEditor = this.getView().byId("image")
- if (!oFile) {
- return
+ onSaveAsPress: async function () {
+ let view = this.getView();
+ let controller = view.getController();
+ let oImageEditor = view.byId("image");
+ oImageEditor.openSaveDialog();
+ controller.openUrl("https://people.sap.com/", true);
+ },
+ onImageLoaded: async function (oEvent) {
+ let view = this.getView();
+ let oImageEditor = view.byId("image");
+ oImageEditor.zoomToFit();
+ oImageEditor.setCropAreaByRatio(1, 1);
+ oImageEditor.setMode(SuiteLibrary.ImageEditorMode.CropRectangle);
+ },
+ onFileChange: async function (oEvent) {
+ var oFile = oEvent.getParameter("files")[0],
+ oImageEditor = this.getView().byId("image");
+ if (!oFile) {
+ return;
+ }
+ this.getView().getModel().setProperty("/blocked", true);
+ await oImageEditor.setSrc(oFile);
+ },
+ onGHImportPressed: async function (oEvent) {
+ var oModel = this.getView().getModel();
+ // Get Rate Limit
+ $.get(
+ "/gh_rate_limit",
+ function (resp) {
+ oModel.setProperty("/ghRateLimit", resp);
+ this.askForGHUsername();
+ }.bind(this)
+ );
+ },
+ askForGHUsername: function () {
+ var oModel = this.getView().getModel();
+ if (!this.oUsernameDialog) {
+ this.oUsernameDialog = new Dialog({
+ title: "Enter Github Username",
+ content: new sap.m.VBox({
+ justifyContent: "Center",
+ items: [
+ new sap.m.Input({
+ value: "{/username}",
+ }).addStyleClass("sapUiTinyMarginBottom"),
+ new sap.m.MessageStrip({
+ type: "Information",
+ showIcon: true,
+ text: "Github api rate limit {/ghRateLimit/rate/remaining} / {/ghRateLimit/rate/limit}",
+ }),
+ ],
+ }).addStyleClass("sapUiTinyMargin"),
+ beginButton: new sap.m.Button({
+ type: sap.m.ButtonType.Emphasized,
+ text: "OK",
+ press: function () {
+ // Check Username
+ let username = oModel.getProperty("/username");
+ if (username && username.length > 0) {
+ this.getGHProfilePicture(username);
+ } else {
+ MessageToast.show("Please provide a username");
}
- this.getView().getModel().setProperty("/blocked", true)
- await oImageEditor.setSrc(oFile)
+ this.oUsernameDialog.close();
+ }.bind(this),
+ }),
+ endButton: new sap.m.Button({
+ text: "Close",
+ press: function () {
+ this.oUsernameDialog.close();
+ }.bind(this),
+ }),
+ });
+ // to get access to the controller's model
+ this.getView().addDependent(this.oUsernameDialog);
+ }
+
+ this.oUsernameDialog.open();
+ },
- }
- })
- }
-)
\ No newline at end of file
+ getGHProfilePicture: function (username) {
+ let view = this.getView();
+ let controller = view.getController();
+ let oImageEditor = view.byId("image");
+ controller.startBusy();
+ // Get URL
+ let dataURL;
+ // Get processed image and set to image editor src
+ $.post(`/gh_profile_pic/${username}`, function (resp) {
+ dataURL = "data:image/png;base64," + resp;
+ oImageEditor.setSrc(dataURL);
+ controller.endBusy(controller);
+ }).fail(function () {
+ controller.endBusy(controller);
+ MessageToast.show("error");
+ });
+ },
+ });
+ }
+);
diff --git a/app/profilePic/profilePic/view/App.view.xml b/app/profilePic/profilePic/view/App.view.xml
index abb2e60..9347cec 100644
--- a/app/profilePic/profilePic/view/App.view.xml
+++ b/app/profilePic/profilePic/view/App.view.xml
@@ -14,15 +14,12 @@
+
-
-
-
-
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 66a72b5..4277f5a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@sap/logging": "^6.1.0",
"@sap/textbundle": "^4.1.0",
"accept-language-parser": "^1.5.0",
+ "axios": "^0.26.0",
"event-loop-lag": "^1.4.0",
"express": "^4.17.2",
"glob": "^7.2.0",
@@ -316,6 +317,14 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
+ "node_modules/axios": {
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
+ "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
+ "dependencies": {
+ "follow-redirects": "^1.14.8"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1234,6 +1243,25 @@
"node": ">=6"
}
},
+ "node_modules/follow-redirects": {
+ "version": "1.14.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
+ "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -3403,6 +3431,14 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
+ "axios": {
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
+ "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
+ "requires": {
+ "follow-redirects": "^1.14.8"
+ }
+ },
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -4134,6 +4170,11 @@
"locate-path": "^3.0.0"
}
},
+ "follow-redirects": {
+ "version": "1.14.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
+ "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
+ },
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
diff --git a/package.json b/package.json
index aa9ca00..95079c3 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
"@sap/logging": "^6.1.0",
"@sap/textbundle": "^4.1.0",
"accept-language-parser": "^1.5.0",
+ "axios": "^0.26.0",
"event-loop-lag": "^1.4.0",
"express": "^4.17.2",
"glob": "^7.2.0",
diff --git a/routes/ghProfilePicture.js b/routes/ghProfilePicture.js
new file mode 100644
index 0000000..d216c77
--- /dev/null
+++ b/routes/ghProfilePicture.js
@@ -0,0 +1,101 @@
+import sharp from "sharp";
+import * as svg from "../utils/svgRender.js";
+import axios from "axios";
+
+/**
+ * Route for handling GH profile picture import
+ * @param {Object} app - Express application instance
+ */
+export default function (app) {
+ const addImage = (base64, format, width, height) => {
+ return `
+
+
+ `;
+ };
+
+ const addRect = (width, height) => {
+ return ` `;
+ };
+ const addPeace = (width, height, username) => {
+ return `☮️ ${username}`;
+ };
+
+ const addStyles = (width) => {
+ return `
+
+
+
+
+
+
+
+ \n`;
+ };
+
+ // GH Profile Picture
+ app.post("/gh_profile_pic/:username", async (req, res) => {
+ const username = req.params.username;
+
+ // get github user data
+ const { data: ghData } = await axios.get(
+ `https://api.github.com/users/${username}`
+ );
+
+ // download image
+ const { data: imgBuffer } = await axios.get(ghData.avatar_url, {
+ responseType: "arraybuffer",
+ });
+
+ // get metadata
+ const metadata = await sharp(imgBuffer).metadata();
+ var imgWidth = metadata.width;
+ var imgHeight = metadata.height;
+ console.log(metadata);
+
+ // generate svg
+ let body =
+ svg.svgHeader(imgWidth, imgHeight) +
+ addStyles(imgWidth) +
+ addImage(
+ await imgBuffer.toString("base64"),
+ metadata.format,
+ imgHeight,
+ imgWidth
+ ) +
+ addRect(imgWidth, imgHeight) +
+ addPeace(imgWidth, imgHeight, username) +
+ svg.svgEnd();
+
+ const png = await sharp(Buffer.from(body)).png().toBuffer();
+ const pngOut = await png.toString("base64");
+ res.type("image/png").status(200).send(pngOut);
+ });
+
+ // GH Profile Picture
+ app.get("/gh_rate_limit", async (req, res) => {
+ // get github user data
+ const { data: ghRateLimit } = await axios.get(
+ "https://api.github.com/rate_limit"
+ );
+ res.status(200).send(ghRateLimit);
+ });
+}