diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index 98a5f8aa..d22bc865 100755 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -1,11 +1,12 @@ import os import ast -import copy import sys import re +import copy import time import base64 import json +import random import liquid import logging import urllib3 @@ -504,10 +505,12 @@ class AppBase: except Exception as e: print(f"[WARNING] Failed adding parameter for logs: {e}") - # FIXME: Adding retries here. try: finished = False for i in range (0, 10): + # Random sleeptime between 0 and 1 second, with 0.1 increments + sleeptime = float(random.randint(0, 10) / 10) + try: ret = requests.post(url, headers=headers, json=action_result, timeout=10, verify=False) @@ -516,29 +519,29 @@ class AppBase: finished = True break else: - self.logger.info(f"[ERROR] RESP: {ret.text}") + self.logger.info(f"[ERROR] Bad resp {ret.status_code}: {ret.text}") except requests.exceptions.RequestException as e: self.logger.info(f"[DEBUG] Request problem: {e}") - time.sleep(0.1) + time.sleep(sleeptime) #time.sleep(5) continue except TimeoutError as e: self.logger.info(f"[DEBUG] Timeout or request: {e}") - time.sleep(0.1) + time.sleep(sleeptime) #time.sleep(5) continue except requests.exceptions.ConnectionError as e: self.logger.info(f"[DEBUG] Connectionerror: {e}") - time.sleep(0.1) + time.sleep(sleeptime) #time.sleep(5) continue except http.client.RemoteDisconnected as e: self.logger.info(f"[DEBUG] Remote: {e}") - time.sleep(0.1) + time.sleep(sleeptime) #time.sleep(5) continue @@ -555,8 +558,11 @@ class AppBase: # Not sure why this would work tho :) action_result["status"] = "FAILURE" action_result["result"] = json.dumps({"success": False, "reason": "POST error: Failed connecting to %s over 10 retries to the backend" % url}) - self.logger.info(f"[DEBUG] Before typeerror stream result - NOT finished after 10 requests") - ret = requests.post("%s%s" % (self.base_url, stream_path), headers=headers, json=action_result, verify=False) + self.logger.info(f"[ERROR] Before typeerror stream result - NOT finished after 10 requests") + + #ret = requests.post("%s%s" % (self.base_url, stream_path), headers=headers, json=action_result, verify=False) + self.send_result(action_result, {"Content-Type": "application/json", "Authorization": "Bearer %s" % self.authorization}, "/api/v1/streams") + return self.logger.info(f"""[DEBUG] Successful request result request: Status= {ret.status_code} & Response= {ret.text}. Action status: {action_result["status"]}""") except requests.exceptions.ConnectionError as e: diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 274bde57..abb8c18e 100755 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -1,6 +1,6 @@ module shuffle-shared -replace github.com/shuffle/shuffle-shared => ../../../../git/shuffle-shared +//replace github.com/shuffle/shuffle-shared => ../../../../git/shuffle-shared go 1.19 @@ -19,7 +19,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/h2non/filetype v1.1.3 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.4.41 + github.com/shuffle/shuffle-shared v0.4.47 golang.org/x/crypto v0.9.0 google.golang.org/api v0.125.0 google.golang.org/appengine v1.6.7 diff --git a/frontend/src/components/Appsearch.jsx b/frontend/src/components/Appsearch.jsx index 090dc620..7408dad5 100644 --- a/frontend/src/components/Appsearch.jsx +++ b/frontend/src/components/Appsearch.jsx @@ -22,10 +22,9 @@ import { import aa from 'search-insights' const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240") const Appsearch = props => { - const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList} = props + const { maxRows, showName, showSuggestion, isMobile, globalUrl, parsedXs, newSelectedApp, setNewSelectedApp, defaultSearch, showSearch, ConfiguredHits, userdata, cy, isCreatorPage, actionImageList, setActionImageList, setUserSpecialzedApp } = props const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"; - //const alert = useAlert(); const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs //const theme = useTheme(); @@ -41,45 +40,6 @@ const Appsearch = props => { const borderRadius = 3 window.title = "Shuffle | Apps | Find and integration any app" - const setUserSpecialzedApp = (user, data) => { - // var data = newfields] - console.log("data value", data) - const appData = {"user_id":user,"specialized_apps":[{}]} - console.log("User Check for appdata:", user) - appData["specialized_apps"][0]["name"] = data["name"] - appData["specialized_apps"][0]["image"] = data["image_url"] - appData["specialized_apps"][0]["category"] = data["categories"].toString() - console.log("AppData:",appData) - console.log("setActionImageList",setActionImageList) - console.log("actionImageList",actionImageList) - - const finalData = actionImageList.concat(appData["specialized_apps"]) - appData["specialized_apps"]=finalData - fetch(globalUrl + "/api/v1/users/updateuser", { - method: "PUT", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify(appData), - credentials: "include", - }) - .then((response) => { - if (response.status !== 200) { - console.log("Status not 200 for set creator :O!"); - } - toast("Sucessfully updated specialzed app.") - return response.json(); - }) - .then((responseJson) => { - if (!responseJson.success && responseJson.reason !== undefined) { - toast("Failed updating user: " + responseJson.reason); - } - }) - .catch((error) => { - console.log(error); - }); - }; // value={currentRefinement} const SearchBox = ({currentRefinement, refine, isSearchStalled} ) => { @@ -180,13 +140,8 @@ const Appsearch = props => { setMouseHoverIndex(-1) }} onClick={() => { if(isCreatorPage === true){ - console.log("data:",data) - console.log("userdata.id",userdata.id) - console.log("is creator", isCreatorPage) - if (setNewSelectedApp !== undefined) { - // setUserSpecialzedApp = data + if (setNewSelectedApp !== undefined && setUserSpecialzedApp !== undefined) { setUserSpecialzedApp(userdata.id, data) - //setActionImageList(userdata.id, data) } } if (setNewSelectedApp !== undefined) { diff --git a/frontend/src/components/Branding.jsx b/frontend/src/components/Branding.jsx index e565a013..9dd40791 100644 --- a/frontend/src/components/Branding.jsx +++ b/frontend/src/components/Branding.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import ReactGA from 'react-ga4'; import theme from "../theme.jsx"; +import { ToastContainer, toast } from "react-toastify" import { Paper, @@ -14,22 +15,87 @@ import { //import { useAlert const Branding = (props) => { - const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props; - //const alert = useAlert(); - const [publishingInfo, setPublishingInfo] = useState(""); + const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props; + //const alert = useAlert(); + const [publishingInfo, setPublishingInfo] = useState(""); + const [publishRequirements, setPublishRequirements] = useState([]) - // Should enable / disable org branding - const handleChangePublishing = () => { - console.log("Handle change publishing"); - } + + const handleEditOrg = (joinStatus) => { + const data = { + "org_id": selectedOrganization.id, + "creator_config": joinStatus, + }; + + const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`; + fetch(url, { + mode: "cors", + method: "POST", + body: JSON.stringify(data), + credentials: "include", + crossDomain: true, + withCredentials: true, + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === false) { + toast("Failed updating org: ", responseJson.reason); + } else { + if (joinStatus == "join") { + setPublishingInfo("Your organization is now part of the Creator Incentive Program. You can now create and publish content to your organization's page. You can also create a creator account to manage your organization's content.") + } else { + setPublishingInfo("Your organization is no longer part of the Creator Incentive Program. You can still create a creator account to manage your organization's content.") + } + handleGetOrg(selectedOrganization.id); + } + }) + ) + .catch((error) => { + toast("Err: " + error.toString()); + }); + }; + + // Should enable / disable org branding + const handleChangePublishing = () => { + console.log("Handle change publishing"); + + if (selectedOrganization.creator_id == "") { + handleEditOrg("join") + } else { + handleEditOrg("leave") + } + } const isOrganizationReady = () => { + console.log("Is organization ready?") + // A simple checklist to ensure the button shows up properly if (selectedOrganization.name === selectedOrganization.org) { + const comment = "Change the name of your organization" + if (!publishRequirements.includes(comment)) { + setPublishRequirements([...publishRequirements, comment]) + } + + return false; + } + + // Check if it's a suborg + if (selectedOrganization.creator_org !== "") { + const comment = "Child orgs can't become creators" + if (!publishRequirements.includes(comment)) { + setPublishRequirements([...publishRequirements, comment]) + } return false; } if (selectedOrganization.large_image === "" || selectedOrganization.large_image === theme.palette.defaultImage) { + const comment = "Add a logo for your organization" + if (!publishRequirements.includes(comment)) { + setPublishRequirements([...publishRequirements, comment]) + } return false; } @@ -38,40 +104,58 @@ const Branding = (props) => { return (