diff --git a/sefaria/model/trend.py b/sefaria/model/trend.py
index ed8518287a..c2d9b8306d 100644
--- a/sefaria/model/trend.py
+++ b/sefaria/model/trend.py
@@ -7,8 +7,6 @@
import time
from datetime import datetime, date, timedelta
-from py import process
-
from . import abstract as abst
from . import user_profile
from . import text
diff --git a/static/js/BookPage.jsx b/static/js/BookPage.jsx
index be769caa79..3730d19961 100644
--- a/static/js/BookPage.jsx
+++ b/static/js/BookPage.jsx
@@ -11,7 +11,7 @@ import {
AdminToolHeader,
CategoryChooser,
TitleVariants,
- CategoryHeader, requestWithCallBack
+ CategoryHeader
} from './Misc';
import {ContentText} from "./ContentText";
import {validateMarkdownLinks} from "./AdminEditor";
@@ -1293,7 +1293,8 @@ const EditTextInfo = function({initTitle, close}) {
const deleteObj = () => {
setSavingStatus(true);
const url = `/api/v2/index/${enTitle}`;
- requestWithCallBack({url, type: "DELETE", redirect: () => window.location.href = `/texts`});
+ Sefaria.adminEditorApiRequest(url, null, null, "DELETE")
+ .then(() => window.location.href = '/texts');
}
const renderCollectiveTitle = () => {
if (!creatingCollectiveTitle) {
diff --git a/static/js/CategoryEditor.jsx b/static/js/CategoryEditor.jsx
index 61f5b2c80e..f7636786aa 100644
--- a/static/js/CategoryEditor.jsx
+++ b/static/js/CategoryEditor.jsx
@@ -2,7 +2,7 @@ import {CategoryChooser, InterfaceText, ToggleSet} from "./Misc";
import Sefaria from "./sefaria/sefaria";
import $ from "./sefaria/sefariaJquery";
import {AdminEditor} from "./AdminEditor";
-import {requestWithCallBack, AdminToolHeader} from "./Misc";
+import {AdminToolHeader} from "./Misc";
import React, {useState, useRef} from "react";
const displayOptionForSources = (child) => {
@@ -84,7 +84,9 @@ const ReorderEditor = ({close, type="", postURL="", redirect="", origItems = []}
else if (type === 'sources') {
postCategoryData = {sources: tocItems};
}
- requestWithCallBack({url: postURL, data: postCategoryData, setSavingStatus, redirect: () => window.location.href = redirect})
+ Sefaria.adminEditorApiRequest(postURL, null, postCategoryData)
+ .then(() => window.location.href = redirect)
+ .finally(() => setSavingStatus(false));
}
return
@@ -187,7 +189,9 @@ const CategoryEditor = ({origData={}, close, origPath=[]}) => {
if (urlParams.length > 0) {
url += `?${urlParams.join('&')}`;
}
- requestWithCallBack({url, data: postCategoryData, setSavingStatus, redirect: () => window.location.href = "/texts/"+fullPath});
+ Sefaria.adminEditorApiRequest(url, null, postCategoryData)
+ .then(() => window.location.href = "/texts/"+fullPath)
+ .finally(() => setSavingStatus(false));
}
@@ -197,7 +201,8 @@ const CategoryEditor = ({origData={}, close, origPath=[]}) => {
return;
}
const url = `/api/category/${origPath.concat(origData.origEn).join("/")}`;
- requestWithCallBack({url, type: "DELETE", redirect: () => window.location.href = `/texts`});
+ Sefaria.adminEditorApiRequest(url, null, null, "DELETE")
+ .then(() => window.location.href = `/texts`);
}
const primaryOptions = [
{name: "true", content: Sefaria._("True"), role: "radio", ariaLabel: Sefaria._("Set Primary Status to True") },
diff --git a/static/js/Misc.jsx b/static/js/Misc.jsx
index f5645ee130..e0b43c77a0 100644
--- a/static/js/Misc.jsx
+++ b/static/js/Misc.jsx
@@ -1045,29 +1045,6 @@ class ToggleOption extends Component {
}
}
- //style={this.props.style}
-
-const requestWithCallBack = ({url, setSavingStatus, redirect, type="POST", data={}, redirect_params}) => {
- let ajaxPayload = {url, type};
- if (type === "POST") {
- ajaxPayload.data = {json: JSON.stringify(data)};
- }
- $.ajax({
- ...ajaxPayload,
- success: function(result) {
- if ("error" in result) {
- if (setSavingStatus) {
- setSavingStatus(false);
- }
- alert(result.error);
- } else {
- redirect();
- }
- }
- }).fail(function() {
- alert(Sefaria._("Something went wrong. Sorry!"));
- });
-}
const TopicToCategorySlug = function(topic, category=null) {
//helper function for AdminEditor
@@ -1676,7 +1653,7 @@ const TopicPictureUploader = ({slug, callback, old_filename, caption}) => {
const deleteImage = () => {
const old_filename_wout_url = old_filename.split("/").slice(-1);
const url = `${Sefaria.apiHost}/api/topics/images/${slug}?old_filename=${old_filename_wout_url}`;
- requestWithCallBack({url, type: "DELETE", redirect: () => alert("Deleted image.")});
+ Sefaria.adminEditorApiRequest(url, null, null, "DELETE").then(() => alert("Deleted image."));
callback("");
fileInput.current.value = "";
}
@@ -3385,7 +3362,6 @@ export {
AdminToolHeader,
CategoryChooser,
TitleVariants,
- requestWithCallBack,
OnInView,
TopicPictureUploader,
ImageWithCaption
diff --git a/static/js/SourceEditor.jsx b/static/js/SourceEditor.jsx
index e95cef8588..1755c74efe 100644
--- a/static/js/SourceEditor.jsx
+++ b/static/js/SourceEditor.jsx
@@ -1,7 +1,7 @@
import Sefaria from "./sefaria/sefaria";
import $ from "./sefaria/sefariaJquery";
import {AdminEditor} from "./AdminEditor";
-import {requestWithCallBack, Autocompleter, InterfaceText} from "./Misc";
+import {Autocompleter, InterfaceText} from "./Misc";
import React, {useState} from "react";
import {useRef} from "react";
@@ -46,10 +46,16 @@ const SourceEditor = ({topic, close, origData={}}) => {
const save = async function () {
setSavingStatus(true);
let refInUrl = isNew ? displayRef : origData.ref;
- let url = `/api/ref-topic-links/${Sefaria.normRef(refInUrl)}`;
- let postData = {"topic": topic, "is_new": isNew, 'new_ref': displayRef, 'interface_lang': Sefaria.interfaceLang};
- postData['description'] = {"title": data.enTitle, "prompt": data.prompt, "ai_context": data.ai_context, "review_state": "edited"};
- requestWithCallBack({url, data: postData, setSavingStatus, redirect: () => window.location.href = "/topics/"+topic});
+ const payload = {
+ new_ref: displayRef,
+ topic,
+ is_new: isNew,
+ interface_lang: Sefaria.interfaceLang,
+ description: {"title": data.enTitle, "prompt": data.prompt, "ai_context": data.ai_context, "review_state": "edited"},
+ }
+ Sefaria.postRefTopicLink(refInUrl, payload)
+ .then(() => window.location.href = `/topics/${topic}`)
+ .finally(() => setSavingStatus(false));
}
const handleChange = (x) => {
@@ -86,8 +92,9 @@ const SourceEditor = ({topic, close, origData={}}) => {
}
const deleteTopicSource = function() {
- const url = `/api/ref-topic-links/${origData.ref}?topic=${topic}&interface_lang=${Sefaria.interfaceLang}`;
- requestWithCallBack({url, type: "DELETE", redirect: () => window.location.href = `/topics/${topic}`});
+ const url = `/api/ref-topic-links/${Sefaria.normRef(origData.ref)}?topic=${topic}&interface_lang=${Sefaria.interfaceLang}`;
+ Sefaria.adminEditorApiRequest(url, null, null, "DELETE")
+ .then(() => window.location.href = `/topics/${topic}`);
}
const previousTitleItemRef = useRef(data.enTitle ? "Previous Title" : null); //use useRef to make value null even if component re-renders
const previousPromptItemRef = useRef(data.prompt ? "Previous Prompt" : null);
diff --git a/static/js/Story.jsx b/static/js/Story.jsx
index 12bf3df64c..8aaacc0d89 100644
--- a/static/js/Story.jsx
+++ b/static/js/Story.jsx
@@ -170,14 +170,14 @@ const ReviewStateIndicatorLang = ({reviewState, markReviewed}) => {
}
const markReviewedPostRequest = (lang, topic, topicLink) => {
- const postData = {
+ const payload = {
"topic": topic,
"is_new": false,
'new_ref': topicLink.ref,
'interface_lang': lang === 'en' ? 'english' : 'hebrew',
'description' : {...topicLink.descriptions[lang], 'review_state': 'reviewed'}
};
- return Sefaria.postToApi(`/api/ref-topic-links/${topicLink.ref}`, {}, postData);
+ return Sefaria.postRefTopicLink(topicLink.ref, payload);
}
const useReviewState = (topic, topicLink) => {
diff --git a/static/js/TopicEditor.jsx b/static/js/TopicEditor.jsx
index 88fc3f1092..2d279ebb76 100644
--- a/static/js/TopicEditor.jsx
+++ b/static/js/TopicEditor.jsx
@@ -1,5 +1,5 @@
import Sefaria from "./sefaria/sefaria";
-import {InterfaceText, requestWithCallBack, TopicPictureUploader} from "./Misc";
+import {InterfaceText, TopicPictureUploader} from "./Misc";
import $ from "./sefaria/sefariaJquery";
import {AdminEditor} from "./AdminEditor";
import {Reorder} from "./CategoryEditor";
@@ -109,7 +109,9 @@ const TopicEditor = ({origData, onCreateSuccess, close, origWasCat}) => {
const saveReorderedSubtopics = function () {
const url = `/api/topic/reorder`;
const postCategoryData = {topics: sortedSubtopics};
- requestWithCallBack({url, data: postCategoryData, setSavingStatus, redirect: () => window.location.href = "/topics"});
+ Sefaria.adminEditorApiRequest(url, null, postCategoryData)
+ .then(() => window.location.href = "/topics")
+ .finally(() => setSavingStatus(false));
}
const prepData = () => {
@@ -189,7 +191,7 @@ const TopicEditor = ({origData, onCreateSuccess, close, origWasCat}) => {
const deleteObj = function() {
const url = `/api/topic/delete/${data.origSlug}`;
- requestWithCallBack({url, type: "DELETE", redirect: () => window.location.href = "/topics"});
+ Sefaria.adminEditorApiRequest(url, null, null, "DELETE").then(() => window.location.href = "/topics");
}
let items = ["Title", "Hebrew Title", "English Description", "Hebrew Description", "Category Menu", "English Alternate Titles", "Hebrew Alternate Titles",];
if (isCategory) {
diff --git a/static/js/TopicPage.jsx b/static/js/TopicPage.jsx
index 44c25fc2b0..0d25a0dac8 100644
--- a/static/js/TopicPage.jsx
+++ b/static/js/TopicPage.jsx
@@ -344,7 +344,7 @@ const generatePrompts = async(topicSlug, linksToGenerate) => {
});
const payload = {ref_topic_links: linksToGenerate};
try {
- await Sefaria.postToApi(`/api/topics/generate-prompts/${topicSlug}`, {}, payload);
+ await Sefaria.apiRequestWithBody(`/api/topics/generate-prompts/${topicSlug}`, {}, payload);
const refValues = linksToGenerate.map(item => item.ref).join(", ");
alert("The following prompts are generating: " + refValues);
} catch (error) {
@@ -359,7 +359,7 @@ const publishPrompts = async (topicSlug, linksToPublish) => {
ref.descriptions[lang]["published"] = true;
});
try {
- const response = await Sefaria.postToApi(`/api/ref-topic-links/bulk`, {}, linksToPublish);
+ const response = await Sefaria.apiRequestWithBody(`/api/ref-topic-links/bulk`, {}, linksToPublish);
const refValues = response.map(item => item.anchorRef).join(", ");
const shouldRefresh = confirm("The following prompts have been published: " + refValues + ". Refresh page to see results?");
if (shouldRefresh) {
diff --git a/static/js/TopicSearch.jsx b/static/js/TopicSearch.jsx
index c736cc72cf..60e098b1cd 100644
--- a/static/js/TopicSearch.jsx
+++ b/static/js/TopicSearch.jsx
@@ -68,27 +68,21 @@ class TopicSearch extends Component {
const srefs = this.props.srefs;
const update = this.props.update;
const reset = this.reset;
- $.post("/api/ref-topic-links/" + Sefaria.normRef(this.props.srefs), {"json": postJSON}, async function (data) {
- if (data.error) {
- alert(data.error);
- } else {
+ Sefaria.postRefTopicLink(Sefaria.normRef(this.props.srefs), postJSON).then(async () => {
const sectionRef = await Sefaria.getRef(Sefaria.normRef(srefs)).sectionRef;
srefs.map(sref => {
- if (!Sefaria._refTopicLinks[sref]) {
- Sefaria._refTopicLinks[sref] = [];
- }
- Sefaria._refTopicLinks[sref].push(data);
+ if (!Sefaria._refTopicLinks[sref]) {
+ Sefaria._refTopicLinks[sref] = [];
+ }
+ Sefaria._refTopicLinks[sref].push(data);
});
if (!Sefaria._refTopicLinks[sectionRef]) {
- Sefaria._refTopicLinks[sectionRef] = [];
+ Sefaria._refTopicLinks[sectionRef] = [];
}
Sefaria._refTopicLinks[sectionRef].push(data);
update();
reset();
alert("Topic added.");
- }
- }).fail(function (xhr, status, errorThrown) {
- alert("Unfortunately, there may have been an error saving this topic information: " + errorThrown);
});
}
diff --git a/static/js/sefaria/sefaria.js b/static/js/sefaria/sefaria.js
index ecffc50cd5..231e3e9e37 100644
--- a/static/js/sefaria/sefaria.js
+++ b/static/js/sefaria/sefaria.js
@@ -623,27 +623,52 @@ Sefaria = extend(Sefaria, {
firstName: firstName,
lastName: lastName,
};
- return await Sefaria.postToApi(`/api/subscribe/${email}`, null, payload);
+ return await Sefaria.apiRequestWithBody(`/api/subscribe/${email}`, null, payload);
},
subscribeSteinsaltzNewsletter: async function(firstName, lastName, email) {
const payload = {firstName, lastName};
- return await Sefaria.postToApi(`/api/subscribe/steinsaltz/${email}`, null, payload);
+ return await Sefaria.apiRequestWithBody(`/api/subscribe/steinsaltz/${email}`, null, payload);
},
-
- postToApi: async function(url, urlParams, payload) {
+ postRefTopicLink: function(refInUrl, payload) {
+ const url = `/api/ref-topic-links/${Sefaria.normRef(refInUrl)}`;
+ // payload will need to be refactored once /api/ref-topic-links takes a more standard input
+ return Sefaria.adminEditorApiRequest(url, null, payload);
+ },
+ adminEditorApiRequest: async function(url, urlParams, payload, method="POST") {
+ /**
+ * Wraps apiRequestWithBody() with basic alerting if response has an error
+ */
+ let result;
+ try {
+ result = await Sefaria.apiRequestWithBody(url, urlParams, payload, method);
+ } catch (e) {
+ alert(Sefaria._("Something went wrong. Sorry!"));
+ throw e;
+ }
+ if (result.error) {
+ alert(result.error);
+ throw result.error;
+ } else {
+ return result;
+ }
+ },
+ apiRequestWithBody: async function(url, urlParams, payload, method="POST") {
+ /**
+ * Generic function for performing an API request with a payload. Payload and urlParams are optional and will not be used if falsy.
+ */
let apiUrl = this.apiHost + url;
if (urlParams) {
apiUrl += '?' + new URLSearchParams(urlParams).toString();
}
const response = await fetch(apiUrl, {
- method: "POST",
+ method,
mode: 'same-origin',
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
'Content-Type': 'application/json'
},
credentials: 'same-origin',
- body: JSON.stringify(payload)
+ body: payload && JSON.stringify(payload)
});
if (!response.ok) {