diff --git a/CHANGELOG.md b/CHANGELOG.md index fe10f74..21cf32b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.2] + +### Breaking changes +- Notion API has changed. Maybe you get this error: "400 error on get_block() call",the fix is in here https://github.com/jamalex/notion-py/issues/292 but you need to modify manually the library. Meanwhile I am waiting for the library owner to update it. +- If you make a lot of request to notion API, means adding lot of content in a short amount of time, you may get now a 429 error(Too Many Requests). I may look into finding a solution or workaround to this, but it is a problem on notion's not my repo or @jamalex notion-py repo. + +### Added + +- Added collections! Now you can have different collections or databases, so you can add the content to the collection you choose. More info here as you need to change your current notion setup: https://github.com/elblogbruno/NotionAI-MyMind/wiki/Notion-AI-My-Mind-Collections + +### Fixed + +- Added more exceptions for error handling. +- Added notification for Notion's recent API change that limits api requests. + ## [2.0.1] ### Added @@ -69,6 +84,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed server issues adding callback capabilities. Before some websites images were not added due to timeouts. +[2.0.2]: https://github.com/elblogbruno/NotionAI-MyMind/releases/tag/2.0.2 [2.0.1]: https://github.com/elblogbruno/NotionAI-MyMind/releases/tag/2.0.1 [2.0]: https://github.com/elblogbruno/NotionAI-MyMind/releases/tag/2.0 [1.9]: https://github.com/elblogbruno/NotionAI-MyMind/releases/tag/1.9 diff --git a/Chrome Extension/css/collection.css b/Chrome Extension/css/collection.css new file mode 100644 index 0000000..27a8aa6 --- /dev/null +++ b/Chrome Extension/css/collection.css @@ -0,0 +1,127 @@ +/* + * Notification Component + */ + #collection-notification { + font-family: Avenir, sans-serif !important; + position: fixed; + right: 30px; + top: 30px; + box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.1); + border-radius: 4px; + width: 350px; + box-sizing: border-box; + user-select: none; + + animation: caimmNotificationSlideIn 300ms ease-out forwards; + animation-delay: 300ms; + opacity: 0; + will-change: opacity, transform; + z-index: 2147483647; +} + +#collection-notification[status="error"] .collection-notification-inner { + border: 2px solid #FF0000 !important; +} + +#collection-notification[status="limited"] .collection-notification-inner { + background: #FF5924 !important; + border: none !important; +} +#collection-notification[status="success"] .collection-notification-inner { + border: 2px solid coral!important; +} + +#collection-notification[closing="true"] { + pointer-events: none !important; + animation: caimmNotificationSlideOut 300ms ease-out forwards; +} + +#collection-notification .collection-notification-wrap { + overflow: hidden; + border-radius: 4px; +} + +#collection-notification .collection-notification-inner { + border-radius: 4px; + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + background: #FFFFFF; + color: #000000 !important; + position: relative; + z-index: 3; + min-height: 90px; + padding: 20px; + box-sizing: border-box; + border: 1px solid #EFEFEF; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15); + cursor: pointer; +} + +#collection-notification .collection-notification-inner img { + width: 30px; + margin: 0 20px; +} + +#collection-notification .collection-notification-inner span { + color: inherit !important; + font-family: Avenir, sans-serif !important; + font-weight: normal !important; + font-size: 20px !important; + line-height: 26px !important; + letter-spacing: 0 !important; + text-transform: none !important; +} + + +/* +Buttons +*/ +.collection-button-div button { + background-color: white; + color: black; + border-radius: 4px; + border: 3px solid coral; + display: block; + margin: 5px; +} + +.collection-button-div { + display: flex; + flex-direction: column; + justify-content: normal; +} + +/* Add a background color on hover */ +.collection-button-div button:hover { + background-color: #f1f1f1; +} + +/* + * Animations + */ + +@keyframes caimmNotificationSlideIn { + 0% { + opacity: 0; + transform: translateY(30px); + } + + 100% { + opacity: 1; + transform: translateY(0px); + } +} + +@keyframes caimmNotificationSlideOut { + 0% { + opacity: 1; + transform: translateY(0px); + } + + 100% { + opacity: 0; + transform: translateY(-30px); + } +} diff --git a/Chrome Extension/js/background.js b/Chrome Extension/js/background.js index 86228db..d29dbdc 100644 --- a/Chrome Extension/js/background.js +++ b/Chrome Extension/js/background.js @@ -15,6 +15,11 @@ const menuConfig = [ title: "Open server", id: "naimm-open", contexts: [ "browser_action" ] + }, + { + title: "Refresh collections", + id: "naimm-collections-refresh", + contexts: [ "browser_action" ] } ]; @@ -43,7 +48,10 @@ chrome.runtime.onInstalled.addListener(function(details){ openNewTab("https://github.com/elblogbruno/NotionAI-MyMind/wiki/Extension-Changelog"); } }); - +// //when browser loads it gets the mind structure. Currently deprecated as it makes a lot of request to notion api. +// chrome.webNavigation.onCompleted.addListener(function(details) { +// GetMindStructure(); +// }); // Browser Action chrome.browserAction.onClicked.addListener((tab) => { @@ -68,22 +76,31 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { else if (menuItemId === "naimm-open-mind") { openMindUrl(); } + else if (menuItemId === "naimm-collections-refresh") { + GetMindStructure(); + } }); -async function AddUrlToMind(tab) { +async function GetMindStructure() { let mainUrl = await getFromStorage("serverIP"); const req = new XMLHttpRequest(); if(!isEmpty(mainUrl)){ const baseUrl = mainUrl; - var url = tab.url; - var title = tab.title; - const urlParams = `add_url_to_mind?url=${url}&title=${title}`; + const urlParams = `get_mind_structure`; req.open("GET", baseUrl+urlParams, true); req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - parseAndSwitchResponse(this.responseText); + //var jsonData = JSON.parse(this.responseText); + // return jsonData; + chrome.storage.sync.set({ "struct" : this.responseText }, function() { + if (chrome.runtime.error) { + console.log("Runtime error."); + } + console.log("Succesfully saved data"); + }); + switchResponse("-2"); } else if (this.status === 0) { switchResponse("-1"); } @@ -94,16 +111,28 @@ async function AddUrlToMind(tab) { } } -async function AddTextToMind(info,tab) { +async function AddUrlToMind(tab) { let mainUrl = await getFromStorage("serverIP"); - const req = new XMLHttpRequest(); + if(!isEmpty(mainUrl)){ const baseUrl = mainUrl; + let struct = await getFromStorage("struct"); + + createCollectionHandler( + () => + showCollectionPopup(String(struct) , (result) => addUrlRequest(tab,baseUrl,result)) + ); - var text = info.selectionText; + }else{ + switchResponse("-1"); + } +} +async function addUrlRequest(tab,baseUrl,collection_index) +{ + const req = new XMLHttpRequest(); var url = tab.url; - urlParams = `add_text_to_mind?url=${url}&text=${text}`; - + var title = tab.title; + const urlParams = `add_url_to_mind?url=${url}&title=${title}&collection_index=${collection_index}`; req.open("GET", baseUrl+urlParams, true); req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { @@ -113,52 +142,94 @@ async function AddTextToMind(info,tab) { } } req.send(); +} + +//Adds text to mind +async function AddTextToMind(info,tab) { + let mainUrl = await getFromStorage("serverIP"); + if(!isEmpty(mainUrl)){ + const baseUrl = mainUrl; + + let struct = await getFromStorage("struct"); + createCollectionHandler( + () => + showCollectionPopup(String(struct) , (result) => addTextRequest(info,tab,baseUrl,result)) + ); + }else{ switchResponse("-1"); } } +async function addTextRequest(info,tab,baseUrl,collection_index){ + const req = new XMLHttpRequest(); + + var text = info.selectionText; + var url = tab.url; + urlParams = `add_text_to_mind?url=${url}&collection_index=${collection_index}&text=${text}`; + + req.open("GET", baseUrl+urlParams, true); + req.onreadystatechange = function() { // Call a function when the state changes. + if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { + parseAndSwitchResponse(this.responseText); + } else if (this.status === 0) { + switchResponse("-1"); + } + } + req.send(); +} async function ProcessSelection(info,tab) { let mainUrl = await getFromStorage("serverIP"); - const req = new XMLHttpRequest(); if(!isEmpty(mainUrl)){ const baseUrl = mainUrl; - var urlParams = ""; - - var url = info["linkUrl"]; - switch (info["mediaType"]) { - case 'image': - var src = info["srcUrl"]; - var image_src_url = info["pageUrl"]; - urlParams = `add_image_to_mind?url=${url}&image_src=${src}&image_src_url=${image_src_url}`; - break; - case 'video': - var src = info["srcUrl"]; - var video_src_url = info["pageUrl"]; - urlParams = `add_video_to_mind?url=${url}&video_src=${src}&video_src_url=${video_src_url}`; - break; - case 'audio': - var src = info["srcUrl"]; - var image_src_url = info["pageUrl"]; - urlParams = `add_audio_to_mind?url=${url}&audio_src=${src}&audio_src_url=${audio_src_url}`; - break; - default: - break; - } - req.open("GET", baseUrl+urlParams, true); - req.send(); - - req.onreadystatechange = function() { // Call a function when the state changes. - if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - parseAndSwitchResponse(this.responseText); - } else if (this.status === 0) { - switchResponse("-1"); - } - } + + let struct = await getFromStorage("struct"); + createCollectionHandler( + () => + showCollectionPopup(String(struct) , (result) => addSelectionToMind(info,baseUrl,result)) + ); + + }else{ switchResponse("-1"); } } +async function addSelectionToMind(info,baseUrl,collection_index){ + const req = new XMLHttpRequest(); + + var urlParams = ""; + + var url = info["linkUrl"]; + switch (info["mediaType"]) { + case 'image': + var src = info["srcUrl"]; + var image_src_url = info["pageUrl"]; + urlParams = `add_image_to_mind?collection_index=${collection_index}&url=${url}&image_src=${src}&image_src_url=${image_src_url}`; + break; + case 'video': + var src = info["srcUrl"]; + var video_src_url = info["pageUrl"]; + urlParams = `add_video_to_mind?collection_index=${collection_index}&url=${url}&video_src=${src}&video_src_url=${video_src_url}`; + break; + case 'audio': + var src = info["srcUrl"]; + var image_src_url = info["pageUrl"]; + urlParams = `add_audio_to_mind?collection_index=${collection_index}&url=${url}&audio_src=${src}&audio_src_url=${audio_src_url}`; + break; + default: + break; + } + req.open("GET", baseUrl+urlParams, true); + req.send(); + + req.onreadystatechange = function() { // Call a function when the state changes. + if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { + parseAndSwitchResponse(this.responseText); + } else if (this.status === 0) { + switchResponse("-1"); + } + } +} function parseAndSwitchResponse(response_from_api){ var myObj = JSON.parse(response_from_api); @@ -173,10 +244,21 @@ function switchResponse(status_code,block_url,status_text,text_response) showNotification({ message: "Error during accessing server. Make sure the ip/port are corrects, and the server is running.", status: "error", - redirect: "https://github.com/elblogbruno/NotionAI-MyMind#love-to-try-it", + redirect: "https://github.com/elblogbruno/NotionAI-MyMind/wiki/Common-Issues", }) ); - }else{ + } + else if (status_code == '-2'){ + createHandler( + () => + showNotification({ + message: "Succesfully refreshed available collections.", + status: "success", + redirect: "https://github.com/elblogbruno/NotionAI-MyMind/wiki/Common-Issues", + }) + ); + } + else{ createHandler( () => showNotification({ @@ -216,10 +298,67 @@ chrome.cookies.onChanged.addListener(function(info) } }); + chrome.runtime.onMessage.addListener(function(request, sender) { - openNewTab(request.redirect); + if(Number.isInteger(request.index)){ + //alert(request.index); + }else{ + openNewTab(request.redirect); + } }); +// undefined +function createCollectionHandler(callback) { + chrome.tabs.insertCSS({ + file: "css/collection.css", + }); + + const config = { file: "js/collectionPopupCreate.js" }; + + if (usePromise) { + browser.tabs.executeScript(config).then(callback); + } else { + chrome.tabs.executeScript(config, callback); + } +} +//We have a callback here from when user chooses a collection index, so we call the function that makes a request to the api with the index. +function showCollectionPopup(structure,callback_from_caller) { + props = { + structure, + } + + function callback() { + chrome.tabs.executeScript({file: 'js/collectionPopupBehaviour.js'}, + function (result) { + chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + if (request.action === 'done') { + console.log(request.result); + sendResponse({ action: 'next', arg: 2 }); + callback_from_caller(request.result); + chrome.runtime.onMessage.removeListener(arguments.callee); + } + // uncomment this if code is also asynchronous + return true; + }); + + } + ); + }; + + const config = { + code: ` + window.caimm = {}; + ${Object.entries(props).map(([key, value]) => `window.caimm.${key} = ${value};`).join('')} + ` + }; + + if (usePromise) { + browser.tabs.executeScript(config).then(callback); + } else { + chrome.tabs.executeScript(config, callback); + } +} + // undefined function createHandler(callback) { chrome.tabs.insertCSS({ diff --git a/Chrome Extension/js/collectionPopupBehaviour.js b/Chrome Extension/js/collectionPopupBehaviour.js new file mode 100644 index 0000000..6950ce1 --- /dev/null +++ b/Chrome Extension/js/collectionPopupBehaviour.js @@ -0,0 +1,73 @@ +(() => { + const usePromise = typeof browser !== "undefined"; + + const { structure } = window.caimm; + + var jsonData = structure; + + const notification = document.getElementById("collection-notification"); + + notification.removeAttribute("closing"); + if (status && status !== "undefined") notification.setAttribute("status", status); + + const notificationWrap = document.createElement("div"); + notificationWrap.className = "collection-notification-wrap"; + + const notificationInner = document.createElement("div"); + notificationInner.className = "collection-notification-inner"; + + const notificationText = document.createElement("span"); + + if (jsonData.structure.length == 1){ + notificationText.innerText = "Only one available. Will be default:"; + }else{ + notificationText.innerText = "Available collections:"; + } + + + notificationInner.appendChild(notificationText); + + const buttonInner = document.createElement("div"); + buttonInner.className = "collection-button-div"; + var index1 = 0; + + for (let index = 0; index < jsonData.structure.length; index++) + { + const element = jsonData.structure[index]; + var btn = document.createElement("button"); + var t = document.createTextNode(element.collection_name); + btn.appendChild(t); + + btn.onclick = function(){ + index1 = index; + var msg = { action: 'done', result: index }; + chrome.runtime.sendMessage(msg, function(response) { + if (response.action === 'next') { + notification.setAttribute("closing", true); + } + }); + }; + + buttonInner.appendChild(btn); + } + + + + notificationInner.append(buttonInner); + notificationWrap.appendChild(notificationInner); + + + notification.innerHTML = ""; + notification.appendChild(notificationWrap); + + setTimeout(() => { + if (jsonData.structure.length == 1){ + var msg = { action: 'done', result: 0 }; + chrome.runtime.sendMessage(msg, function(response) { + if (response.action === 'next') { + notification.setAttribute("closing", true); + } + }); + } + }, 2000); +})(); diff --git a/Chrome Extension/js/collectionPopupCreate.js b/Chrome Extension/js/collectionPopupCreate.js new file mode 100644 index 0000000..ffeeaa5 --- /dev/null +++ b/Chrome Extension/js/collectionPopupCreate.js @@ -0,0 +1,8 @@ +(() => { + if (document.getElementById("collection-notification")) return false; + + const notification = document.createElement("div"); + notification.setAttribute("id", "collection-notification"); + + document.body.appendChild(notification); +})(); \ No newline at end of file diff --git a/Chrome Extension/js/options.js b/Chrome Extension/js/options.js index 4626341..af43621 100644 --- a/Chrome Extension/js/options.js +++ b/Chrome Extension/js/options.js @@ -1,11 +1,22 @@ function saveSettings() { var ip = document.getElementById("serverip").value; - chrome.storage.sync.set({ "serverIP" : ip }, function() { - if (chrome.runtime.error) { - console.log("Runtime error."); + if(ValidURL(ip)){ + + var res = ip.charAt(ip.length-1); + if (res != "/"){ + ip = ip+"/"; } - alert("Settings were successfully saved ! " + ip); - }); + + chrome.storage.sync.set({ "serverIP" : ip }, function() { + if (chrome.runtime.error) { + console.log("Runtime error."); + } + alert("Settings were successfully saved! " + ip); + }); + }else{ + alert("Please make sure you enter a correct url.") + } + } function restore_options() { @@ -18,7 +29,15 @@ function restore_options() { cookies_utils.getTokenFromCookie(); } +function ValidURL(str) { + var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/; + if(!regex .test(str)) { + return false; + } else { + return true; + } +} document.addEventListener('DOMContentLoaded', function() { restore_options(); diff --git a/Chrome Extension/manifest.json b/Chrome Extension/manifest.json index 0e8d460..d83dbb1 100644 --- a/Chrome Extension/manifest.json +++ b/Chrome Extension/manifest.json @@ -3,7 +3,7 @@ "name": "Notion AI My Mind", "description": "This extension allows to click to add any image or website to your MIND in notion, and forget about everything else.", - "version": "1.0.8", + "version": "1.0.9", "browser_action": { "default_icon": "icon/icon.png", diff --git a/Extension - CHANGELOG.md b/Extension - CHANGELOG.md index b61be53..076cce9 100644 --- a/Extension - CHANGELOG.md +++ b/Extension - CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.9] + +### Added + +- Added collections! Now you can have different collections or databases, so you can add the content to the collection you choose. More info here as you need to change your current notion setup: https://github.com/elblogbruno/NotionAI-MyMind/wiki/Notion-AI-My-Mind-Collections + + +### Fixed + +- Removed unused code and permissions. +- Now it checks if you enter an incorrect server url. + ## [1.0.8] ### Added diff --git a/Firefox Extension/css/collection.css b/Firefox Extension/css/collection.css new file mode 100644 index 0000000..27a8aa6 --- /dev/null +++ b/Firefox Extension/css/collection.css @@ -0,0 +1,127 @@ +/* + * Notification Component + */ + #collection-notification { + font-family: Avenir, sans-serif !important; + position: fixed; + right: 30px; + top: 30px; + box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.1); + border-radius: 4px; + width: 350px; + box-sizing: border-box; + user-select: none; + + animation: caimmNotificationSlideIn 300ms ease-out forwards; + animation-delay: 300ms; + opacity: 0; + will-change: opacity, transform; + z-index: 2147483647; +} + +#collection-notification[status="error"] .collection-notification-inner { + border: 2px solid #FF0000 !important; +} + +#collection-notification[status="limited"] .collection-notification-inner { + background: #FF5924 !important; + border: none !important; +} +#collection-notification[status="success"] .collection-notification-inner { + border: 2px solid coral!important; +} + +#collection-notification[closing="true"] { + pointer-events: none !important; + animation: caimmNotificationSlideOut 300ms ease-out forwards; +} + +#collection-notification .collection-notification-wrap { + overflow: hidden; + border-radius: 4px; +} + +#collection-notification .collection-notification-inner { + border-radius: 4px; + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + background: #FFFFFF; + color: #000000 !important; + position: relative; + z-index: 3; + min-height: 90px; + padding: 20px; + box-sizing: border-box; + border: 1px solid #EFEFEF; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15); + cursor: pointer; +} + +#collection-notification .collection-notification-inner img { + width: 30px; + margin: 0 20px; +} + +#collection-notification .collection-notification-inner span { + color: inherit !important; + font-family: Avenir, sans-serif !important; + font-weight: normal !important; + font-size: 20px !important; + line-height: 26px !important; + letter-spacing: 0 !important; + text-transform: none !important; +} + + +/* +Buttons +*/ +.collection-button-div button { + background-color: white; + color: black; + border-radius: 4px; + border: 3px solid coral; + display: block; + margin: 5px; +} + +.collection-button-div { + display: flex; + flex-direction: column; + justify-content: normal; +} + +/* Add a background color on hover */ +.collection-button-div button:hover { + background-color: #f1f1f1; +} + +/* + * Animations + */ + +@keyframes caimmNotificationSlideIn { + 0% { + opacity: 0; + transform: translateY(30px); + } + + 100% { + opacity: 1; + transform: translateY(0px); + } +} + +@keyframes caimmNotificationSlideOut { + 0% { + opacity: 1; + transform: translateY(0px); + } + + 100% { + opacity: 0; + transform: translateY(-30px); + } +} diff --git a/Firefox Extension/js/background.js b/Firefox Extension/js/background.js index 96dcc9d..f5e14c6 100644 --- a/Firefox Extension/js/background.js +++ b/Firefox Extension/js/background.js @@ -15,6 +15,11 @@ const menuConfig = [ title: "Open server", id: "naimm-open", contexts: [ "browser_action" ] + }, + { + title: "Refresh collections", + id: "naimm-collections-refresh", + contexts: [ "browser_action" ] } ]; @@ -66,23 +71,30 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { else if (menuItemId === "naimm-open-mind") { openMindUrl(); } + else if (menuItemId === "naimm-collections-refresh") { + GetMindStructure(); + } }); -async function AddUrlToMind(tab) { +async function GetMindStructure() { let mainUrl = await getFromStorage("serverIP"); const req = new XMLHttpRequest(); if(!isEmpty(mainUrl)){ const baseUrl = mainUrl; - var url = tab.url; - var title = tab.title; - const urlParams = `add_url_to_mind?url=${url}&title=${title}`; - + const urlParams = `get_mind_structure`; req.open("GET", baseUrl+urlParams, true); req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - parseAndSwitchResponse(this.responseText); + //var jsonData = JSON.parse(this.responseText); + // return jsonData; + browser.storage.local.set({ "struct" : this.responseText }, function() { + if (browser.runtime.error) { + console.log("Runtime error."); + } + console.log("Succesfully saved data"); + }); } else if (this.status === 0) { switchResponse("-1"); } @@ -93,18 +105,29 @@ async function AddUrlToMind(tab) { } } -async function AddTextToMind(info,tab) { +async function AddUrlToMind(tab) { let mainUrl = await getFromStorage("serverIP"); - const req = new XMLHttpRequest(); + if(!isEmpty(mainUrl)){ const baseUrl = mainUrl; + let struct = await getFromStorage("struct"); + + createCollectionHandler( + () => + showCollectionPopup(String(struct) , (result) => addUrlRequest(tab,baseUrl,result)) + ); - var text = info.selectionText; + }else{ + switchResponse("-1"); + } +} +async function addUrlRequest(tab,baseUrl,collection_index) +{ + const req = new XMLHttpRequest(); var url = tab.url; - urlParams = `add_text_to_mind?url=${url}&text=${text}`; - + var title = tab.title; + const urlParams = `add_url_to_mind?url=${url}&title=${title}&collection_index=${collection_index}`; req.open("GET", baseUrl+urlParams, true); - req.onreadystatechange = function() { // Call a function when the state changes. if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { parseAndSwitchResponse(this.responseText); @@ -113,54 +136,96 @@ async function AddTextToMind(info,tab) { } } req.send(); +} + +//Adds text to mind +async function AddTextToMind(info,tab) { + let mainUrl = await getFromStorage("serverIP"); + if(!isEmpty(mainUrl)){ + const baseUrl = mainUrl; + + let struct = await getFromStorage("struct"); + + createCollectionHandler( + () => + showCollectionPopup(String(struct) , (result) => addTextRequest(info,tab,baseUrl,result)) + ); + }else{ switchResponse("-1"); } } +async function addTextRequest(info,tab,baseUrl,collection_index){ + const req = new XMLHttpRequest(); + + var text = info.selectionText; + var url = tab.url; + urlParams = `add_text_to_mind?url=${url}&collection_index=${collection_index}&text=${text}`; + + req.open("GET", baseUrl+urlParams, true); + req.onreadystatechange = function() { // Call a function when the state changes. + if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { + parseAndSwitchResponse(this.responseText); + } else if (this.status === 0) { + switchResponse("-1"); + } + } + req.send(); +} async function ProcessSelection(info,tab) { let mainUrl = await getFromStorage("serverIP"); - const req = new XMLHttpRequest(); if(!isEmpty(mainUrl)){ const baseUrl = mainUrl; - var urlParams = ""; - - var url = info["linkUrl"]; - switch (info["mediaType"]) { - case 'image': - var src = info["srcUrl"]; - var image_src_url = info["pageUrl"]; - urlParams = `add_image_to_mind?url=${url}&image_src=${src}&image_src_url=${image_src_url}`; - break; - case 'video': - var src = info["srcUrl"]; - var video_src_url = info["pageUrl"]; - urlParams = `add_video_to_mind?url=${url}&video_src=${src}&video_src_url=${video_src_url}`; - break; - case 'audio': - var src = info["srcUrl"]; - var image_src_url = info["pageUrl"]; - urlParams = `add_audio_to_mind?url=${url}&audio_src=${src}&audio_src_url=${audio_src_url}`; - break; - default: - break; - } + + let struct = await getFromStorage("struct"); + + createCollectionHandler( + () => + showCollectionPopup(String(struct) , (result) => addSelectionToMind(info,baseUrl,result)) + ); + - req.open("GET", baseUrl+urlParams, true); - req.send(); - - req.onreadystatechange = function() { // Call a function when the state changes. - if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { - parseAndSwitchResponse(this.responseText); - } else if (this.status === 0) { - switchResponse("-1"); - } - } }else{ switchResponse("-1"); } } +async function addSelectionToMind(info,baseUrl,collection_index){ + const req = new XMLHttpRequest(); + + var urlParams = ""; + + var url = info["linkUrl"]; + switch (info["mediaType"]) { + case 'image': + var src = info["srcUrl"]; + var image_src_url = info["pageUrl"]; + urlParams = `add_image_to_mind?collection_index=${collection_index}&url=${url}&image_src=${src}&image_src_url=${image_src_url}`; + break; + case 'video': + var src = info["srcUrl"]; + var video_src_url = info["pageUrl"]; + urlParams = `add_video_to_mind?collection_index=${collection_index}&url=${url}&video_src=${src}&video_src_url=${video_src_url}`; + break; + case 'audio': + var src = info["srcUrl"]; + var image_src_url = info["pageUrl"]; + urlParams = `add_audio_to_mind?collection_index=${collection_index}&url=${url}&audio_src=${src}&audio_src_url=${audio_src_url}`; + break; + default: + break; + } + req.open("GET", baseUrl+urlParams, true); + req.send(); + req.onreadystatechange = function() { // Call a function when the state changes. + if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { + parseAndSwitchResponse(this.responseText); + } else if (this.status === 0) { + switchResponse("-1"); + } + } +} function parseAndSwitchResponse(response_from_api){ var myObj = JSON.parse(response_from_api); @@ -175,10 +240,21 @@ function switchResponse(status_code,block_url,status_text,text_response) showNotification({ message: "Error during accessing server. Make sure the ip/port are corrects, and the server is running.", status: "error", - redirect: "https://github.com/elblogbruno/NotionAI-MyMind#love-to-try-it", + redirect: "https://github.com/elblogbruno/NotionAI-MyMind/wiki/Common-Issues", }) ); - }else{ + } + else if (status_code == '-2'){ + createHandler( + () => + showNotification({ + message: "Succesfully refreshed available collections.", + status: "success", + redirect: "https://github.com/elblogbruno/NotionAI-MyMind/wiki/Common-Issues", + }) + ); + } + else{ createHandler( () => showNotification({ @@ -220,8 +296,63 @@ browser.cookies.onChanged.addListener(function(info) }); browser.runtime.onMessage.addListener(function(request, sender) { - openNewTab(request.redirect); + if(Number.isInteger(request.index)){ + //alert(request.index); + }else{ + openNewTab(request.redirect); + } }); +// undefined +function createCollectionHandler(callback) { + browser.tabs.insertCSS({ + file: "css/collection.css", + }); + + const config = { file: "js/collectionPopupCreate.js" }; + + if (usePromise) { + browser.tabs.executeScript(config).then(callback); + } else { + chrome.tabs.executeScript(config, callback); + } +} +//We have a callback here from when user chooses a collection index, so we call the function that makes a request to the api with the index. +function showCollectionPopup(structure,callback_from_caller) { + props = { + structure, + } + + function callback() { + browser.tabs.executeScript({file: 'js/collectionPopupBehaviour.js'}, + function (result) { + browser.runtime.onMessage.addListener(function(request, sender, sendResponse) { + if (request.action === 'done') { + console.log(request.result); + sendResponse({ action: 'next', arg: 2 }); + callback_from_caller(request.result); + browser.runtime.onMessage.removeListener(arguments.callee); + } + // uncomment this if code is also asynchronous + return true; + }); + + } + ); + }; + + const config = { + code: ` + window.caimm = {}; + ${Object.entries(props).map(([key, value]) => `window.caimm.${key} = ${value};`).join('')} + ` + }; + + if (usePromise) { + browser.tabs.executeScript(config).then(callback); + } else { + chrome.tabs.executeScript(config, callback); + } +} // undefined function createHandler(callback) { diff --git a/Firefox Extension/js/collectionPopupBehaviour.js b/Firefox Extension/js/collectionPopupBehaviour.js new file mode 100644 index 0000000..6950ce1 --- /dev/null +++ b/Firefox Extension/js/collectionPopupBehaviour.js @@ -0,0 +1,73 @@ +(() => { + const usePromise = typeof browser !== "undefined"; + + const { structure } = window.caimm; + + var jsonData = structure; + + const notification = document.getElementById("collection-notification"); + + notification.removeAttribute("closing"); + if (status && status !== "undefined") notification.setAttribute("status", status); + + const notificationWrap = document.createElement("div"); + notificationWrap.className = "collection-notification-wrap"; + + const notificationInner = document.createElement("div"); + notificationInner.className = "collection-notification-inner"; + + const notificationText = document.createElement("span"); + + if (jsonData.structure.length == 1){ + notificationText.innerText = "Only one available. Will be default:"; + }else{ + notificationText.innerText = "Available collections:"; + } + + + notificationInner.appendChild(notificationText); + + const buttonInner = document.createElement("div"); + buttonInner.className = "collection-button-div"; + var index1 = 0; + + for (let index = 0; index < jsonData.structure.length; index++) + { + const element = jsonData.structure[index]; + var btn = document.createElement("button"); + var t = document.createTextNode(element.collection_name); + btn.appendChild(t); + + btn.onclick = function(){ + index1 = index; + var msg = { action: 'done', result: index }; + chrome.runtime.sendMessage(msg, function(response) { + if (response.action === 'next') { + notification.setAttribute("closing", true); + } + }); + }; + + buttonInner.appendChild(btn); + } + + + + notificationInner.append(buttonInner); + notificationWrap.appendChild(notificationInner); + + + notification.innerHTML = ""; + notification.appendChild(notificationWrap); + + setTimeout(() => { + if (jsonData.structure.length == 1){ + var msg = { action: 'done', result: 0 }; + chrome.runtime.sendMessage(msg, function(response) { + if (response.action === 'next') { + notification.setAttribute("closing", true); + } + }); + } + }, 2000); +})(); diff --git a/Firefox Extension/js/collectionPopupCreate.js b/Firefox Extension/js/collectionPopupCreate.js new file mode 100644 index 0000000..ffeeaa5 --- /dev/null +++ b/Firefox Extension/js/collectionPopupCreate.js @@ -0,0 +1,8 @@ +(() => { + if (document.getElementById("collection-notification")) return false; + + const notification = document.createElement("div"); + notification.setAttribute("id", "collection-notification"); + + document.body.appendChild(notification); +})(); \ No newline at end of file diff --git a/Firefox Extension/js/options.js b/Firefox Extension/js/options.js index 7101c91..7afaca6 100644 --- a/Firefox Extension/js/options.js +++ b/Firefox Extension/js/options.js @@ -1,11 +1,21 @@ function saveSettings() { var ip = document.getElementById("serverip").value; - browser.storage.local.set({ "serverIP" : ip }, function() { - if (browser.runtime.error) { - console.log("Runtime error."); + if(ValidURL(ip)){ + + var res = ip.charAt(ip.length-1); + if (res != "/"){ + ip = ip+"/"; } - alert("Settings were successfully saved !" + ip); - }); + + browser.storage.local.set({ "serverIP" : ip }, function() { + if (chrome.runtime.error) { + console.log("Runtime error."); + } + alert("Settings were successfully saved! " + ip); + }); + }else{ + alert("Please make sure you enter a correct url.") + } } function restore_options() { @@ -18,6 +28,15 @@ function restore_options() { cookies_utils.getTokenFromCookie(); } +function ValidURL(str) { + var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/; + if(!regex .test(str)) { + + return false; + } else { + return true; + } +} document.addEventListener('DOMContentLoaded', function() { diff --git a/Firefox Extension/manifest.json b/Firefox Extension/manifest.json index a00089c..516a5ed 100644 --- a/Firefox Extension/manifest.json +++ b/Firefox Extension/manifest.json @@ -3,7 +3,7 @@ "name": "Notion AI My Mind", "description": "This extension allows to click to add any image or website to your MIND in notion, and forget about everything else.", - "version": "1.0.8", + "version": "1.0.9", "browser_action": { "default_icon": "icon/icon.png", diff --git a/Python Server/app/NotionAI/NotionAI.py b/Python Server/app/NotionAI/NotionAI.py index 941e731..5d4aa22 100644 --- a/Python Server/app/NotionAI/NotionAI.py +++ b/Python Server/app/NotionAI/NotionAI.py @@ -3,16 +3,13 @@ from utils.custom_errors import OnImageNotFound, OnUrlNotValid, NoTagsFound -import os import requests -import json -import webbrowser -import socket from threading import Thread from image_tagging.image_tagging import ImageTagging from NotionAI.utils import create_json_response, web_clipper_request, extract_image_from_content, \ - get_current_extension_name + get_current_extension_name, open_browser_at_start +from NotionAI.mind_structure import * class NotionAI: @@ -24,20 +21,7 @@ def __init__(self, logging, port): logging.info("Initiating with a found config file.") self.loaded = self.run(logging) else: # Instead it is the first time running the server, so we open the server url. - self.open_browser_at_start(port) - - def open_browser_at_start(self, port): - hostname = socket.gethostname() - local_ip = socket.gethostbyname(hostname) - final_url = "http://{0}:{1}/".format(str(local_ip), str(port)) - - print("You should go to the homepage and set the credentials. The url will open in your browser now. If can't " - "access a browser you can access {0}".format(final_url)) - - self.logging.info("You should go to the homepage and set the credentials. The url will open in your browser " - "now. If can't access a browser you can access {0}".format(final_url)) - - webbrowser.open(final_url) + open_browser_at_start(port) def run(self, logging, email=None, password=None): loaded = False @@ -65,28 +49,30 @@ def run(self, logging, email=None, password=None): self.token_v2 = token_v2 - print("Token V2: " + str(token_v2)) - - mind_page = self.client.get_block(data['url']) - - self.mind_id = mind_page.id - self.image_tagger = ImageTagging(data, logging) # we initialize the image tagger with our data. - - cv = self.client.get_collection_view(self.data['url']) - - self.collection = cv.collection # collection is our database or "mind" in notion - + self.mind_structure = MindStructure(client=self.client,data=self.data) self.counter = 0 - self.times_to_retry = 5 # if no image is found initially, it will retry this many times loaded = True + except requests.exceptions.HTTPError: self.logging.info("Incorrect token V2 from notion") return loaded - def add_url_to_database(self, url, title): + def set_current_collection(self, index=0): + print("Getting collection at index {}".format(index)) + try: + if self.mind_structure is None: + self.mind_structure = MindStructure(client=self.client, data=self.data) + + collection_id, id = self.mind_structure.get_collection_by_index(index) # collection is our database or "mind" in notion, as be have multiple, if not suplied, it will get the first one as the priority one. + self.collection = self.client.get_collection(collection_id=collection_id) + self.current_mind_id = id + except requests.exceptions.HTTPError as e: + print("Http error : " + str(e)) + + def add_url_to_database(self, url, title, collection_index=0): if url is None or title is None: self.statusCode = 500 return create_json_response(self) @@ -94,6 +80,7 @@ def add_url_to_database(self, url, title): self.logging.info("Adding url to mind: {0} {1}".format(url.encode('utf8'), title.encode('utf8'))) self.statusCode = 200 # at start we asume everything will go ok try: + self.set_current_collection(collection_index) rowId = web_clipper_request(self, url, title) thread = Thread(target=self.add_url_thread, args=(rowId,)) @@ -112,14 +99,16 @@ def add_url_to_database(self, url, title): self.statusCode = 404 return create_json_response(self) - def add_text_to_database(self, text, url): - self.logging.info("Adding text to mind: {0} {1}".format(url.encode('utf8'), text.encode('utf8'))) + def add_text_to_database(self, text, url, collection_index=0): self.statusCode = 200 # at start we asume everything will go ok try: if url == "" or text == "": self.statusCode = 500 return create_json_response(self) else: + self.logging.info("Adding text to mind: {0} {1}".format(url.encode('utf8'), text.encode('utf8'))) + self.set_current_collection(collection_index) + row = self.collection.add_row() self.row = row @@ -140,7 +129,7 @@ def add_text_to_database(self, text, url): self.statusCode = 404 return create_json_response(self) - def add_image_to_database(self, image_src, url=None, image_src_url=None): + def add_image_to_database(self, image_src, url=None, image_src_url=None, collection_index=0): is_local = image_src_url is None and url is None if is_local: @@ -151,6 +140,8 @@ def add_image_to_database(self, image_src, url=None, image_src_url=None): self.statusCode = 200 # at start we asume everything will go ok try: + self.set_current_collection(collection_index) + row = self.collection.add_row() self.row = row @@ -194,56 +185,69 @@ def modify_row_by_id(self, id, title, url): return create_json_response(self) def row_callback(self, record, difference): - if len(self.row.AITagsText) == 0 and len(self.row.mind_extension) == 0 and len(difference[0][-1][0][1]) != 0: - print("Callback from row. Here's what was changed:") - self.page_content = difference[0][-1][0][1] - try: - img_url_list = extract_image_from_content(self, self.page_content, record.id) + try: + if len(self.row.AITagsText) == 0 and len(self.row.mind_extension) == 0 and len(difference[0][-1][0][1]) != 0: + print("Callback from row. Here's what was changed:") + self.page_content = difference[0][-1][0][1] try: - self.row.remove_callbacks(self.row_callback) - self.add_tags_to_row(img_url_list, False) - except NoTagsFound as e: - print(e) - self.add_tags_to_row(None, False) - self.logging.info(e) - except ValueError as e: + img_url_list = extract_image_from_content(self, self.page_content, record.id) + try: + self.row.remove_callbacks(self.row_callback) + self.add_tags_to_row(img_url_list, False) + except NoTagsFound as e: + print(e) + self.add_tags_to_row(None, False) + self.logging.info(e) + except ValueError as e: + print(e) + self.add_tags_to_row(None, False) + self.logging.info(e) + except Exception as e: + self.add_tags_to_row(None, False) + self.logging.info(e) + except OnImageNotFound as e: print(e) self.add_tags_to_row(None, False) self.logging.info(e) - except Exception as e: - self.add_tags_to_row(None, False) - self.logging.info(e) - except OnImageNotFound as e: - print(e) - self.add_tags_to_row(None, False) - self.logging.info(e) - else: - print("This row is added already") + else: + print("This row is added already") + except AttributeError as e: + print(e) + self.logging.info(e) def add_url_thread(self, rowId): self.logging.info("Thread adding url %s: starting", rowId) self.page_content = None + try: + self.row = self.client.get_block(rowId) + self.row.add_callback(self.row_callback) - self.row = self.client.get_block(rowId) - self.row.add_callback(self.row_callback) - - while self.page_content is None: - self.row.refresh() + while self.page_content is None: + self.row.refresh() - self.logging.info("Thread %s: finishing", rowId) + self.logging.info("Thread %s: finishing", rowId) + except requests.exceptions.HTTPError as e: + print(e) + self.statusCode = 429 + self.logging.info(e) def add_text_thread(self, url, text): - row = self.row - self.logging.info("Add text Thread %s: starting", row.id) + try: + row = self.row + self.logging.info("Add text Thread %s: starting", row.id) - row.name = "Extract from " + url + row.name = "Extract from " + url - text_block = row.children.add_new(TextBlock) - text_block.title = text + text_block = row.children.add_new(TextBlock) + text_block.title = text - row.person = self.client.current_user - row.url = url - self.logging.info("Add text Thread %s: finished", row.id) + row.person = self.client.current_user + row.url = url + self.row.mind_extension = get_current_extension_name(self.request_platform) + self.logging.info("Add text Thread %s: finished", row.id) + except AttributeError as e: + print(e) + self.logging.info(e) def add_image_thread(self, image_src, url=None, image_src_url=None, is_local=False): row = self.row @@ -264,23 +268,23 @@ def add_image_thread(self, image_src, url=None, image_src_url=None, is_local=Fal self.analyze_image_thread([image_src], row, is_image_local=is_local) def add_tags_to_row(self, img_url_list, is_image_local): - if img_url_list is None or len(img_url_list) == 0: - self.logging.info("No image was found or no tags are available.") - self.row.AITagsText = "no-tags-available" - else: - self.logging.info("Found {0} images.".format(len(img_url_list))) - result = "" - for img_url in img_url_list: - self.logging.info("Adding tags to image {0}".format(img_url)) - tags = self.image_tagger.get_tags(img_url, is_image_local) - self.logging.info("Tags from image {0} : {1}".format(img_url, tags)) - result = tags + "," + result - self.row.AITagsText = result - self.row.mind_extension = get_current_extension_name(self.request_platform) - - # sets the current platform making the request, so we know if content is added from phone or desktop - def set_mind_extension(self, platform): - self.request_platform = platform + try: + if img_url_list is None or len(img_url_list) == 0: + self.logging.info("No image was found or no tags are available.") + self.row.AITagsText = "no-tags-available" + else: + self.logging.info("Found {0} images.".format(len(img_url_list))) + result = "" + for img_url in img_url_list: + self.logging.info("Adding tags to image {0}".format(img_url)) + tags = self.image_tagger.get_tags(img_url, is_image_local) + self.logging.info("Tags from image {0} : {1}".format(img_url, tags)) + result = tags + "," + result + self.row.AITagsText = result + self.row.mind_extension = get_current_extension_name(self.request_platform) + except AttributeError as e: + print(e) + self.logging.info(e) def analyze_image_thread(self, image_src, row, is_image_local=False): try: @@ -298,3 +302,7 @@ def analyze_image_thread(self, image_src, row, is_image_local=False): except OnImageNotFound as e: print(e) self.logging.info(e) + + # sets the current platform making the request, so we know if content is added from phone or desktop + def set_mind_extension(self, platform): + self.request_platform = platform diff --git a/Python Server/app/NotionAI/mind_structure.py b/Python Server/app/NotionAI/mind_structure.py new file mode 100644 index 0000000..0b77287 --- /dev/null +++ b/Python Server/app/NotionAI/mind_structure.py @@ -0,0 +1,54 @@ +from utils.custom_errors import OnCollectionNotAvailable +from NotionAI.utils import get_joined_url +import json +import os + +class MindStructure: + def __init__(self, client, data): + self.client = client + self.data = data + + def get_collection_by_index(self, index=0): + structure = self.get_mind_structure_from_json() + if len(structure) > 0: + collection_id = structure[index]["collection_id"] + collection_block_page_id = structure[index]["collection_block_page_id"] + return collection_id, collection_block_page_id + else: + self.logging.info("No structure or collection was found") + raise OnCollectionNotAvailable + + def get_mind_structure(self, structure_url=None): + if structure_url is None: + structure_url = self.data['url'] + + structure = self.client.get_block(structure_url) + structure.refresh() + available_connections = [] + for child in structure.children: + if len(child.title) > 0: + x = { + "collection_name": child.title, + "collection_id": child.collection.id, + "collection_url": get_joined_url(child.id), + "collection_block_page_id": child.id + } + available_connections.append(x) + else: + print("Blank structure found.") + + self.save_mind_structure(available_connections) + return available_connections + + def save_mind_structure(self, available_connection): + with open('mind_structure.json', 'w') as f: + json.dump(available_connection, f) + + def get_mind_structure_from_json(self): + if os.path.isfile('mind_structure.json'): + structure = [] + with open('mind_structure.json') as json_file: + structure = json.load(json_file) + return structure + else: + return self.get_mind_structure() diff --git a/Python Server/app/NotionAI/utils.py b/Python Server/app/NotionAI/utils.py index ad43b48..144db1d 100644 --- a/Python Server/app/NotionAI/utils.py +++ b/Python Server/app/NotionAI/utils.py @@ -6,6 +6,8 @@ import requests import validators +import webbrowser +import socket ##Makes a web request to the notion web clipper API to add url's and returns the rowId @@ -28,7 +30,7 @@ def web_clipper_request(self, url, title): } data_dict = { "type": "block", - "blockId": "{}".format(self.mind_id), + "blockId": "{}".format(self.current_mind_id), "property": "P#~d", "items": [url_object], "from": "chrome" @@ -41,6 +43,7 @@ def web_clipper_request(self, url, title): response_text = response.text json_response = json.loads(response_text) rowId = json_response['createdBlockIds'][0] + print(rowId) return rowId else: raise OnUrlNotValid("Invalid url was sent", self) @@ -74,12 +77,12 @@ def extract_image_from_content(self, page_content, row_id): content = row.get('content') sleep(0.15) self.counter += 1 - return self.extract_image_from_content(content, row_id) + return extract_image_from_content(content, row_id) return list_of_img_url def create_json_response(self, status_code=None, rowId=None): - url = "https://github.com/elblogbruno/NotionAI-MyMind#love-to-try-it" + url = "https://github.com/elblogbruno/NotionAI-MyMind/wiki/Common-Issues" block_title = "-1" block_attached_url = "-1" @@ -88,9 +91,7 @@ def create_json_response(self, status_code=None, rowId=None): status_code = self.statusCode if rowId is not None: - rowIdExtracted = rowId.split("-") - str1 = ''.join(str(e) for e in rowIdExtracted) - url = "https://www.notion.so/" + str1 + url = get_joined_url(rowId) row = self.client.get_block(rowId) block_title = row.title block_attached_url = row.url @@ -126,3 +127,24 @@ def get_current_extension_name(platform): return "phone-app-extension" else: return "browser-extension" + + +def open_browser_at_start(self, port): + hostname = socket.gethostname() + local_ip = socket.gethostbyname(hostname) + final_url = "http://{0}:{1}/".format(str(local_ip), str(port)) + + print("You should go to the homepage and set the credentials. The url will open in your browser now. If can't " + "access a browser you can access {0}".format(final_url)) + + self.logging.info("You should go to the homepage and set the credentials. The url will open in your browser " + "now. If can't access a browser you can access {0}".format(final_url)) + + webbrowser.open(final_url) + + +def get_joined_url(rowId): + rowIdExtracted = rowId.split("-") + str1 = ''.join(str(e) for e in rowIdExtracted) + url = "https://www.notion.so/" + str1 + return url diff --git a/Python Server/app/server.py b/Python Server/app/server.py index 93f1b9b..58cdfee 100644 --- a/Python Server/app/server.py +++ b/Python Server/app/server.py @@ -1,6 +1,6 @@ import logging -from quart import Quart, render_template, flash, request +from quart import Quart, render_template, flash, request, jsonify from werkzeug.utils import secure_filename import secrets @@ -8,7 +8,6 @@ from NotionAI.NotionAI import * from utils.utils import ask_server_port, save_options, save_data, createFolder - UPLOAD_FOLDER = '../app/uploads/' ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp']) @@ -25,20 +24,25 @@ async def add_url_to_mind(): url = request.args.get('url') title = request.args.get('title') + collection_index = request.args.get('collection_index') notion.set_mind_extension(request.user_agent.platform) - return str(notion.add_url_to_database(url, title)) + return str(notion.add_url_to_database(url, title,int(collection_index))) @app.route('/add_text_to_mind') async def add_text_to_mind(): url = request.args.get('url') text = request.args.get('text') + collection_index = request.args.get('collection_index') notion.set_mind_extension(request.user_agent.platform) - if len(request.args) > 2: + + if len(request.args) > 4: l = request.args.to_dict() - text = text + " & " + str(list(l)[-1]) + addition_list = list(l)[3:] + addition = '&'.join(str(text) for text in addition_list) + text = text + "&" + addition - return str(notion.add_text_to_database(text, url)) + return str(notion.add_text_to_database(text, url,int(collection_index))) @app.route('/add_image_to_mind') @@ -46,8 +50,15 @@ async def add_image_to_mind(): url = request.args.get('url') image_src = request.args.get('image_src') image_src_url = request.args.get('image_src_url') + collection_index = request.args.get('collection_index') + notion.set_mind_extension(request.user_agent.platform) - return str(notion.add_image_to_database(image_src, url, image_src_url)) + return str(notion.add_image_to_database(image_src, url, image_src_url,int(collection_index))) + + +@app.route('/get_mind_structure') +async def get_mind_structure(): + return jsonify(structure=notion.mind_structure.get_mind_structure()) @app.route('/modify_element_by_id') diff --git a/Python Server/app/templates/options.html b/Python Server/app/templates/options.html index 24ea862..69d21a0 100644 --- a/Python Server/app/templates/options.html +++ b/Python Server/app/templates/options.html @@ -16,7 +16,7 @@