def sheet_node_api(request, sheet_id, node_id): if request.method == "GET": sheet_node = get_sheet_node(int(sheet_id),int(node_id)) return jsonResponse(sheet_node, callback=request.GET.get("callback", None)) if request.method == "POST": return jsonResponse({"error": "Unsupported HTTP method."})
def export_to_drive(request, credential, sheet_id): """ Export a sheet to Google Drive. """ http = credential.authorize(httplib2.Http()) service = build('drive', 'v3', http=http) sheet = get_sheet(sheet_id) if 'error' in sheet: return jsonResponse({'error': {'message': sheet["error"]}}) file_metadata = { 'name': strip_tags(sheet['title'].strip()), 'mimeType': 'application/vnd.google-apps.document' } html_string = sheet_to_html_string(sheet) media = MediaIoBaseUpload( StringIO(html_string), mimetype='text/html', resumable=True) new_file = service.files().create(body=file_metadata, media_body=media, fields='webViewLink').execute() return jsonResponse(new_file)
def generate_feedback(request): data = json.loads(request.POST.get('json', {})) fb_type = data.get('type', None) refs = data.get('refs', None) url = data.get('url', None) versions = data.get('currVersions', None) uid = data.get('uid', None) from_email = data.get('email', None) msg = data.get('msg', None) if not from_email: from_email = model.user_profile.UserProfile(id=uid).email if fb_type == "content_issue": to_email = "*****@*****.**" subject = "Correction from website - " + ' / '.join(refs) message_html = msg + "\n\n" + "refs: " + ' / '.join(refs) + "\n" + "versions: " + str(versions) + "\n\n" + "URL: " + url else: to_email = "*****@*****.**" subject = "Feedback from website - " + fb_type.replace("_"," ") message_html = msg + "\n\n" + "URL: " + url try: send_email(subject, message_html, from_email, to_email) return jsonResponse({"status": "ok"}) except: return jsonResponse({"error": _("Sorry, there was an error.")})
def file_upload(request, resize_image=True): from PIL import Image from tempfile import NamedTemporaryFile from sefaria.s3 import HostedFile if request.method == "POST": MAX_FILE_MB = 2 MAX_FILE_SIZE = MAX_FILE_MB * 1024 * 1024 MAX_FILE_DIMENSIONS = (1048, 1048) uploaded_file = request.FILES['file'] if uploaded_file.size > MAX_FILE_SIZE: return jsonResponse({"error": "Uploaded files must be smaller than %dMB." % MAX_FILE_MB}) name, extension = os.path.splitext(uploaded_file.name) with NamedTemporaryFile(suffix=extension) as temp_uploaded_file: temp_uploaded_file.write(uploaded_file.read()) with NamedTemporaryFile(suffix=extension) as temp_resized_file: image = Image.open(temp_uploaded_file) if resize_image: image.thumbnail(MAX_FILE_DIMENSIONS, Image.ANTIALIAS) image.save(temp_resized_file, optimize=True, quality=70) name, extension = os.path.splitext(temp_resized_file.name) hosted_file = HostedFile(filepath=temp_resized_file.name, content_type=uploaded_file.content_type) try: url = hosted_file.upload() return jsonResponse({"status": "success", "url": url}) except: return jsonResponse({"error": "There was an error uploading your file."}) else: return jsonResponse({"error": "Unsupported HTTP method."})
def groups_invite_api(request, group_name, uid_or_email, uninvite=False): """ API for adding or removing group members, or group invitations """ if request.method != "POST": return jsonResponse({"error": "Unsupported HTTP method."}) group = Group().load({"name": group_name}) if not group: return jsonResponse({"error": "No group named %s." % group_name}) if request.user.id not in group.admins: return jsonResponse({"error": "You must be a group admin to invite new members."}) user = UserProfile(email=uid_or_email) if not user.exists(): if uninvite: group.remove_invitation(uid_or_email) message = "Invitation removed." else: group.invite_member(uid_or_email, request.user.id) message = "Invitation sent." else: is_new_member = not group.is_member(user.id) if is_new_member: group.add_member(user.id) from sefaria.model.notification import Notification notification = Notification({"uid": user.id}) notification.make_group_add(adder_id=request.user.id, group_name=group_name) notification.save() message = "Group member added." else: message = "%s is already a member of this group." % user.full_name group_content = group.contents(with_content=True, authenticated=True) return jsonResponse({"group": group_content, "message": message})
def user_sheet_list_api(request, user_id): """ API for listing the sheets that belong to user_id. """ if int(user_id) != request.user.id: return jsonResponse({"error": "You are not authorized to view that."}) return jsonResponse(user_sheets(user_id), callback=request.GET.get("callback", None))
def user_sheet_list_api_with_sort(request, user_id, sort_by="date", limiter=0, offset=0): limiter = int(limiter) offset = int(offset) if int(user_id) != request.user.id: return jsonResponse({"error": "You are not authorized to view that."}) return jsonResponse(user_sheets(user_id, sort_by, limit=limiter, skip=offset), callback=request.GET.get("callback", None))
def sheet_list_api(request): """ API for listing available sheets """ if request.method == "GET": return jsonResponse(sheet_list(), callback=request.GET.get("callback", None)) # Save a sheet if request.method == "POST": if not request.user.is_authenticated(): return jsonResponse({"error": "You must be logged in to save."}) j = request.POST.get("json") if not j: return jsonResponse({"error": "No JSON given in post data."}) sheet = json.loads(j) if "id" in sheet: existing = get_sheet(sheet["id"]) if "error" not in existing and \ not can_edit(request.user, existing) and \ not can_add(request.user, existing): return jsonResponse({"error": "You don't have permission to edit this sheet."}) responseSheet = save_sheet(sheet, request.user.id) if "rebuild" in responseSheet and responseSheet["rebuild"]: # Don't bother adding user links if this data won't be used to rebuild the sheet responseSheet["sources"] = annotate_user_links(responseSheet["sources"]) return jsonResponse(responseSheet)
def add_ref_to_sheet_api(request, sheet_id): """ API to add a source to a sheet using only a ref. """ ref = request.POST.get("ref") if not ref: return jsonResponse({"error": "No ref given in post data."}) return jsonResponse(add_ref_to_sheet(int(sheet_id), ref))
def add_source_to_sheet_api(request, sheet_id): """ API to add a fully formed source (posted as JSON) to sheet_id. """ source = json.loads(request.POST.get("source")) if not source: return jsonResponse({"error": "No source to copy given."}) return jsonResponse(add_source_to_sheet(int(sheet_id), source))
def add_source_to_sheet_api(request, sheet_id): """ API to add a fully formed source (posted as JSON) to sheet_id. The contents of the "source" field will be a dictionary. The input format is similar to, but differs slightly from, the internal format for sources on source sheets. This method reformats the source to the format expected by add_source_to_sheet(). Fields of input dictionary: either `refs` - an array of string refs, indicating a range or `ref` - a string ref or `outsideText` - a string or `outsideBiText` - a dictionary with string fields "he" and "en" or `comment` - a string or `media` - a URL string If the `ref` or `refs` fields are present, the `version`, `he` or `en` fields can further specify the origin or content of text for that ref. """ source = json.loads(request.POST.get("source")) if not source: return jsonResponse({"error": "No source to copy given."}) if "refs" in source and source["refs"]: ref = Ref(source["refs"][0]).to(Ref(source["refs"][-1])) source["ref"] = ref.normal() del source["refs"] if "ref" in source and source["ref"]: ref = Ref(source["ref"]) source["heRef"] = ref.he_normal() if "version" in source or "en" in source or "he" in source: text = {} if "en" in source: text["en"] = source["en"] tc = TextChunk(ref, "he", source["version"]) if source.get("versionLanguage") == "he" else TextChunk(ref, "he") text["he"] = tc.ja().flatten_to_string() del source["en"] elif "he" in source: text["he"] = source["he"] tc = TextChunk(ref, "en", source["version"]) if source.get("versionLanguage") == "en" else TextChunk(ref, "en") text["en"] = tc.ja().flatten_to_string() del source["he"] else: # "version" in source text[source["versionLanguage"]] = TextChunk(ref, source["versionLanguage"], source["version"]).ja().flatten_to_string() other = "he" if source["versionLanguage"] == "en" else "en" text[other] = TextChunk(ref, other).ja().flatten_to_string() source.pop("version", None) source.pop("versionLanguage", None) source["text"] = text note = request.POST.get("note", None) response = add_source_to_sheet(int(sheet_id), source, note=note) return jsonResponse(response)
def private_sheet_list_api(request, partner): partner = partner.replace("-", " ").replace("_", " ") group = Group().load({"name": partner}) if not group: raise Http404 if request.user.is_authenticated() and group.name in [g.name for g in request.user.groups.all()]: return jsonResponse(partner_sheets(partner, True), callback=request.GET.get("callback", None)) else: return jsonResponse(partner_sheets(partner, False), callback=request.GET.get("callback", None))
def copy_source_to_sheet_api(request, sheet_id): """ API to copy a source from one sheet to another. """ copy_sheet = request.POST.get("sheet") copy_source = request.POST.get("source") if not copy_sheet and copy_source: return jsonResponse({"error": "Need both a sheet and source number to copy."}) return jsonResponse(copy_source_to_sheet(int(sheet_id), int(copy_sheet), int(copy_source)))
def private_sheet_list_api(request, group): group = group.replace("-", " ").replace("_", " ") group = Group().load({"name": group}) if not group: raise Http404 if request.user.is_authenticated and group.is_member(request.user.id): return jsonResponse(group_sheets(group, True), callback=request.GET.get("callback", None)) else: return jsonResponse(group_sheets(group, False), callback=request.GET.get("callback", None))
def sheet_api(request, sheet_id): """ API for accessing and individual sheet. """ if request.method == "GET": sheet = get_sheet(int(sheet_id)) return jsonResponse(sheet, callback=request.GET.get("callback", None)) if request.method == "POST": return jsonResponse({"error": "TODO - save to sheet by id"})
def unlike_sheet_api(request, sheet_id): """ API to unlike sheet_id. """ if not request.user.is_authenticated: return jsonResponse({"error": "You must be logged in to like sheets."}) if request.method != "POST": return jsonResponse({"error": "Unsupported HTTP method."}) remove_like_from_sheet(int(sheet_id), request.user.id) return jsonResponse({"status": "ok"})
def add_source_to_sheet_api(request, sheet_id): """ API to add a fully formed source (posted as JSON) to sheet_id. """ source = json.loads(request.POST.get("source")) if not source: return jsonResponse({"error": "No source to copy given."}) if "refs" in source: source["ref"] = Ref(source["refs"][0]).to(Ref(source["refs"][-1])).normal() del source["refs"] return jsonResponse(add_source_to_sheet(int(sheet_id), source))
def get_aliyot_by_parasha_api(request, parasha): response = {"ref":[]}; if parasha == "V'Zot HaBerachah": return jsonResponse({"ref":["Deuteronomy 33:1-7","Deuteronomy 33:8-12","Deuteronomy 33:13-17","Deuteronomy 33:18-21","Deuteronomy 33:22-26","Deuteronomy 33:27-29","Deuteronomy 34:1-12"]}, callback=request.GET.get("callback", None)) else: p = db.parshiot.find({"parasha": parasha}, limit=1).sort([("date", 1)]) p = p.next() for aliyah in p["aliyot"]: response["ref"].append(aliyah) return jsonResponse(response, callback=request.GET.get("callback", None))
def visual_sheet_api(request, sheet_id): """ API for visual source sheet layout """ if not request.user.is_authenticated: return {"error": "You must be logged in to save a sheet layout."} if request.method != "POST": return jsonResponse({"error": "Unsupported HTTP method."}) visualNodes = json.loads(request.POST.get("visualNodes")) zoomLevel = json.loads(request.POST.get("zoom")) add_visual_data(int(sheet_id), visualNodes, zoomLevel) return jsonResponse({"status": "ok"})
def groups_pin_sheet_api(request, group_name, sheet_id): if request.method != "POST": return jsonResponse({"error": "Unsupported HTTP method."}) group = Group().load({"name": group_name}) if not group: return jsonResponse({"error": "No group named %s." % group_name}) if request.user.id not in group.admins: return jsonResponse({"error": "You must be a group admin to invite new members."}) sheet_id = int(sheet_id) group.pin_sheet(sheet_id) group_content = group.contents(with_content=True, authenticated=True) return jsonResponse({"group": group_content, "status": "success"})
def copy_source_to_sheet_api(request, sheet_id): """ API to copy a source from one sheet to another. """ copy_sheet = request.POST.get("sheetID") copy_source = request.POST.get("nodeID") if not copy_sheet and copy_source: return jsonResponse({"error": "Need both a sheet and source node ID to copy."}) source = get_sheet_node(int(copy_sheet), int(copy_source)) del source["node"] response = add_source_to_sheet(int(sheet_id), source) return jsonResponse(response)
def subscribe(request, email): """ API for subscribg is mailing lists, in `lists` url param. Currently active lists are: "Announcements_General", "Announcements_General_Hebrew", "Announcements_Edu", "Announcements_Edu_Hebrew" """ lists = request.GET.get("lists", "") lists = lists.split("|") if len(lists) == 0: return jsonResponse({"error": "Please specifiy a list."}) if subscribe_to_list(lists + ["Newsletter_Sign_Up"], email, direct_sign_up=True): return jsonResponse({"status": "ok"}) else: return jsonResponse({"error": _("Sorry, there was an error.")})
def sheet_api(request, sheet_id): """ API for accessing and individual sheet. """ if request.method == "GET": more_data = request.GET.get('more_data', '0') if more_data == '1': sheet = get_sheet_for_panel(int(sheet_id)) else: sheet = get_sheet(int(sheet_id)) return jsonResponse(sheet, callback=request.GET.get("callback", None)) if request.method == "POST": return jsonResponse({"error": "TODO - save to sheet by id"})
def groups_api(request, group=None): if request.method == "GET": if not group: return jsonResponse({ "private": [g.listing_contents() for g in GroupSet().for_user(request.user.id)], "public": [g.listing_contents() for g in GroupSet({"listed": True, "moderationStatus": {"$ne": "nolist"}}, sort=[("name", 1)])] }) group = Group().load({"name": group}) if not group: return jsonResponse({"error": "No group named '%s'" % group}) is_member = request.user.is_authenticated and group.is_member(request.user.id) group_content = group.contents(with_content=True, authenticated=is_member) return jsonResponse(group_content) else: return groups_post_api(request, group_name=group)
def delete_sheet_api(request, sheet_id): """ Deletes sheet with id, only if the requester is the sheet owner. """ id = int(sheet_id) sheet = db.sheets.find_one({"id": id}) if not sheet: return jsonResponse({"error": "Sheet %d not found." % id}) if request.user.id != sheet["owner"]: return jsonResponse({"error": "Only the sheet owner may delete a sheet."}) db.sheets.remove({"id": id}) return jsonResponse({"status": "ok"})
def text_upload_api(request): if request.method != "POST": return jsonResponse({"error": "Unsupported Method: {}".format(request.method)}) from sefaria.export import import_versions_from_stream message = "" files = request.FILES.getlist("texts[]") for f in files: try: import_versions_from_stream(f, [1], request.user.id) message += "Imported: {}. ".format(f.name) except Exception as e: return jsonResponse({"error": e.message, "message": message}) message = "Successfully imported {} versions".format(len(files)) return jsonResponse({"status": "ok", "message": message})
def cache_stats(request): import resource resp = { 'ref_cache_size': model.Ref.cache_size(), 'memory usage': resource.getrusage(resource.RUSAGE_SELF).ru_maxrss } return jsonResponse(resp)
def wrapper(*args, **kwargs): try: result = func(*args, **kwargs) except exps.InputError as e: logger.warning(u"An exception occurred while running {}. Caught as JSON".format(func.__name__), exc_info=True) return jsonResponse({"error": unicode(e)}) return result
def all_sheets_api(request, limiter, offset=0): limiter = int(limiter) offset = int(offset) response = public_sheets(limit=limiter, skip=offset) response = jsonResponse(response, callback=request.GET.get("callback", None)) response["Cache-Control"] = "max-age=3600" return response
def bulktext_api(request, refs): """ Used by the linker. :param request: :param refs: :return: """ if request.method == "GET": cb = request.GET.get("callback", None) refs = set(refs.split("|")) res = {} for tref in refs: try: oref = model.Ref(tref) lang = "he" if is_hebrew(tref) else "en" he = model.TextChunk(oref, "he").text en = model.TextChunk(oref, "en").text res[tref] = { 'he': he if isinstance(he, basestring) else JaggedTextArray(he).flatten_to_string(), # these could be flattened on the client, if need be. 'en': en if isinstance(en, basestring) else JaggedTextArray(en).flatten_to_string(), 'lang': lang, 'ref': oref.normal(), 'heRef': oref.he_normal(), 'url': oref.url() } except (InputError, ValueError, AttributeError) as e: referer = request.META.get("HTTP_REFERER", "unknown page") logger.warning(u"Linker failed to parse {} from {} : {}".format(tref, referer, e)) res[tref] = {"error": 1} resp = jsonResponse(res, cb) resp['Access-Control-Allow-Origin'] = '*' return resp
def groups_post_api(request, user_id, group_name=None): if request.method == "POST": j = request.POST.get("json") if not j: return jsonResponse({"error": "No JSON given in post data."}) group = json.loads(j) existing = Group().load({"name": group.get("previousName", group["name"])}) if existing: # Don't overwrite existing group when posting to create a new group if "new" in group: return jsonResponse({"error": "A group with this name already exists."}) # check poster is a group admin if user_id not in existing.admins: return jsonResponse({"error": "You do not have permission to edit this group."}) existing.load_from_dict(group) existing.save() else: del group["new"] group["admins"] = [user_id] group["publishers"] = [] group["members"] = [] Group(group).save() return jsonResponse({"status": "ok"}) elif request.method == "DELETE": if not group_name: return jsonResponse({"error": "Please specify a group name in the URL."}) existing = Group().load({"name": group_name}) if existing: if user_id not in existing.admins: return jsonResponse({"error": "You do not have permission to delete this group."}) else: GroupSet({"name": group_name}).delete() return jsonResponse({"status": "ok"}) else: return jsonResponse({"error": "Group named %s does not exist" % group_name}) else: return jsonResponse({"error": "Unsupported HTTP method."})
def bulktext_api(request, refs): """ Used by the linker. :param request: :param refs: :return: """ if request.method == "GET": cb = request.GET.get("callback", None) refs = set(refs.split("|")) g = lambda x: request.GET.get(x, None) min_char = int(g("minChar")) if g("minChar") else None max_char = int(g("maxChar")) if g("maxChar") else None res = bundle_many_texts(refs, g("useTextFamily"), g("asSizedString"), min_char, max_char) resp = jsonResponse(res, cb) return resp
def cache_stats(request): import resource from sefaria.utils.util import get_size from sefaria.model.user_profile import public_user_data_cache # from sefaria.sheets import last_updated resp = { 'ref_cache_size': f'{model.Ref.cache_size():,}', # 'ref_cache_bytes': model.Ref.cache_size_bytes(), # This pretty expensive, not sure if it should run on prod. 'public_user_data_size': f'{len(public_user_data_cache):,}', 'public_user_data_bytes': f'{get_size(public_user_data_cache):,}', # 'sheets_last_updated_size': len(last_updated), # 'sheets_last_updated_bytes': get_size(last_updated), 'memory usage': f'{resource.getrusage(resource.RUSAGE_SELF).ru_maxrss:,}' } return jsonResponse(resp)
def bulktext_api(request, refs): """ Used by the linker. :param request: :param refs: :return: """ if request.method == "GET": cb = request.GET.get("callback", None) useTextFamily = request.GET.get("useTextFamily", None) refs = set(refs.split("|")) res = {} for tref in refs: try: oref = model.Ref(tref) lang = "he" if is_hebrew(tref) else "en" if useTextFamily: text_fam = model.TextFamily(oref, commentary=0, context=0, pad=False) he = text_fam.he en = text_fam.text res[tref] = { 'he': he, 'en': en, 'lang': lang, 'ref': oref.normal(), 'primary_category': text_fam.contents()['primary_category'], 'heRef': oref.he_normal(), 'url': oref.url() } else: he = model.TextChunk(oref, "he").text en = model.TextChunk(oref, "en").text res[tref] = { 'he': he if isinstance(he, basestring) else JaggedTextArray(he).flatten_to_string(), # these could be flattened on the client, if need be. 'en': en if isinstance(en, basestring) else JaggedTextArray(en).flatten_to_string(), 'lang': lang, 'ref': oref.normal(), 'heRef': oref.he_normal(), 'url': oref.url() } except (InputError, ValueError, AttributeError, KeyError) as e: # referer = request.META.get("HTTP_REFERER", "unknown page") # This chatter fills up the logs. todo: put in it's own file # logger.warning(u"Linker failed to parse {} from {} : {}".format(tref, referer, e)) res[tref] = {"error": 1} resp = jsonResponse(res, cb) return resp
def collections_post_api(request, user_id, slug=None): if request.method == "POST": j = request.POST.get("json") if not j: return jsonResponse({"error": "No JSON given in post data."}) collection_data = json.loads(j) if "slug" in collection_data: collection = Collection().load({"slug": collection_data["slug"]}) if not collection: return jsonResponse({"error": "Collection with slug `{}` not found.".format(collection["slug"])}) # check poster is a collection admin if user_id not in collection.admins: return jsonResponse({"error": "You do not have permission to edit this collection."}) collection.load_from_dict(collection_data) collection.save() else: collection_data["admins"] = [user_id] collection = Collection(collection_data) collection.save() return jsonResponse({"status": "ok", "collection": collection.listing_contents(request.user.id)}) elif request.method == "DELETE": if not slug: return jsonResponse({"error": "Please specify a collection in the URL."}) existing = Collection().load({"slug": slug}) if existing: if user_id not in existing.admins: return jsonResponse({"error": "You do not have permission to delete this collection."}) else: CollectionSet({"slug": slug}).delete() return jsonResponse({"status": "ok"}) else: return jsonResponse({"error": "Collection with the slug `{}` does not exist".format(slug)}) else: return jsonResponse({"error": "Unsupported HTTP method."})
def title_regex_api(request, titles): if request.method == "GET": cb = request.GET.get("callback", None) titles = set(titles.split("|")) res = {} errors = [] for title in titles: lang = "he" if is_hebrew(title) else "en" try: re_string = model.library.get_regex_string(title, lang, anchored=False, for_js=True) res[title] = re_string except (AttributeError, AssertionError) as e: # There are normal errors here, when a title matches a schema node, the chatter fills up the logs. # logger.warning(u"Library._build_ref_from_string() failed to create regex for: {}. {}".format(title, e)) errors.append(u"{} : {}".format(title, e)) if len(errors): res["error"] = errors resp = jsonResponse(res, cb) return resp
def title_regex_api(request, titles): if request.method == "GET": cb = request.GET.get("callback", None) titles = set(titles.split("|")) res = {} errors = [] for title in titles: lang = "he" if is_hebrew(title) else "en" try: re_string = model.library.get_regex_string(title, lang, for_js=True) res[title] = re_string except (AttributeError, AssertionError) as e: logger.warning(u"Library._build_ref_from_string() failed to create regex for: {}. {}".format(title, e)) errors.append(u"{} : {}".format(title, e)) if len(errors): res["error"] = errors resp = jsonResponse(res, cb) resp['Access-Control-Allow-Origin'] = '*' return resp
def bulktext_api(request, refs): """ Used by the linker. :param request: :param refs: :return: """ if request.method == "GET": cb = request.GET.get("callback", None) refs = set(refs.split("|")) res = {} for tref in refs: try: oref = model.Ref(tref) lang = "he" if is_hebrew(tref) else "en" he = model.TextChunk(oref, "he").text en = model.TextChunk(oref, "en").text res[tref] = { 'he': he if isinstance(he, basestring) else JaggedTextArray(he).flatten_to_string( ), # these could be flattened on the client, if need be. 'en': en if isinstance(en, basestring) else JaggedTextArray(en).flatten_to_string(), 'lang': lang, 'ref': oref.normal(), 'heRef': oref.he_normal(), 'url': oref.url() } except (InputError, ValueError, AttributeError) as e: referer = request.META.get("HTTP_REFERER", "unknown page") logger.warning( u"Linker failed to parse {} from {} : {}".format( tref, referer, e)) res[tref] = {"error": 1} resp = jsonResponse(res, cb) resp['Access-Control-Allow-Origin'] = '*' return resp
def profile_spam_dashboard(request): from django.contrib.auth.models import User if request.method == 'POST': return jsonResponse({"error": "Unsupported Method: {}".format(request.method)}) else: date = request.GET.get("date", None) if date: date = datetime.strptime(date, '%Y-%m-%d') else: date = request.GET.get("date", datetime.now() - timedelta(days=30)) earliest_new_user_id = User.objects.filter(date_joined__gte=date).order_by('date_joined')[0].id regex = r'.*(?!href=[\'"](\/|http(s)?:\/\/(www\.)?sefaria).+[\'"])(href).*' users_to_check = db.profiles.find( {'$or': [ {'website': {"$ne": ""}, 'bio': {"$ne": ""}, "id": {"$gt": earliest_new_user_id}, "reviewed": {"$ne": True}}, {'bio': {"$regex": regex}, "id": {"$gt": earliest_new_user_id}, "reviewed": {"$ne": True}} ] }) profiles_list = [] for user in users_to_check: history_count = db.user_history.find({'uid': user['id']}).count() if history_count < 10: profiles_list.append({"id": user["id"], "slug": user["slug"], "bio": strip_tags(user["bio"][0:250]), "website": user["website"][0:50]}) return render_template(request, 'spam_dashboard.html', None, { "title": "Potential Spam Profiles since %s" % date.strftime("%Y-%m-%d"), "profiles": profiles_list, "type": "profile", })
def sheets_by_tag_api(request, tag): """ API to retrieve the list of peopke who like sheet_id. """ sheets = get_sheets_by_tag(tag, public=True) sheets = [{ "title": s["title"], "id": s["id"], "owner": s["owner"], "views": s["views"] } for s in sheets] for sheet in sheets: profile = UserProfile(id=sheet["owner"]) sheet["ownerName"] = profile.full_name sheet["ownerImageUrl"] = profile.gravatar_url_small response = {"tag": tag, "sheets": sheets} response = jsonResponse(response, callback=request.GET.get("callback", None)) response["Cache-Control"] = "max-age=3600" return response
def sheet_list_api(request): """ API for listing available sheets """ if request.method == "GET": return jsonResponse(sheet_list(), callback=request.GET.get("callback", None)) # Save a sheet if request.method == "POST": if not request.user.is_authenticated(): key = request.POST.get("apikey") if not key: return jsonResponse({"error": "You must be logged in or use an API key to save."}) apikey = db.apikeys.find_one({"key": key}) if not apikey: return jsonResponse({"error": "Unrecognized API key."}) else: apikey = None j = request.POST.get("json") if not j: return jsonResponse({"error": "No JSON given in post data."}) sheet = json.loads(j) if apikey: if "id" in sheet: sheet["lastModified"] = get_sheet(sheet["id"])["dateModified"] # Usually lastModified gets set on the frontend, so we need to set it here to match with the previous dateModified so that the check in `save_sheet` returns properly user = User.objects.get(id=apikey["uid"]) else: user = request.user if "id" in sheet: existing = get_sheet(sheet["id"]) if "error" not in existing and \ not can_edit(user, existing) and \ not can_add(request.user, existing): return jsonResponse({"error": "You don't have permission to edit this sheet."}) if "group" in sheet: if sheet["group"] not in [group.name for group in user.groups.all()]: sheet["group"] = None responseSheet = save_sheet(sheet, user.id) if "rebuild" in responseSheet and responseSheet["rebuild"]: # Don't bother adding user links if this data won't be used to rebuild the sheet responseSheet["sources"] = annotate_user_links(responseSheet["sources"]) return jsonResponse(responseSheet)
def collections_inclusion_api(request, slug, action, sheet_id): """ API for adding or removing a sheet from a collection """ if request.method != "POST": return jsonResponse({"error": "Unsupported HTTP method."}) collection = Collection().load({"slug": slug}) if not collection: return jsonResponse({"error": "No collection with slug `{}`.".format(slug)}) if not collection.is_member(request.user.id): return jsonResponse({"error": "Only members of this collection my change its contents."}) sheet_id = int(sheet_id) sheet = db.sheets.find_one({"id": sheet_id}) if not sheet: return jsonResponse({"error": "No sheet with id {}.".format(sheet_id)}) if action == "remove": if sheet_id in collection.sheets: collection.sheets.remove(sheet_id) if request.user.id == sheet["owner"] and sheet.get("displayedCollection", None) == collection.slug: sheet["displayedCollection"] = None db.sheets.find_one_and_replace({"id": sheet["id"]}, sheet) else: return jsonResponse({"error": "Sheet with id {} is not in this collection.".format(sheet_id)}) if action == "add": if sheet_id not in collection.sheets: collection.sheets.append(sheet_id) # If a sheet's owner adds it to a collection, and the sheet is not highlighted # in another collection, set it to highlight this collection. if request.user.id == sheet["owner"] and not sheet.get("displayedCollection", None): sheet["displayedCollection"] = collection.slug db.sheets.find_one_and_replace({"id": sheet["id"]}, sheet) collection.save() is_member = request.user.is_authenticated and collection.is_member(request.user.id) sheet = get_sheet_for_panel(int(sheet_id)) sheet_listing = annotate_user_collections([sheet_to_dict(sheet)], request.user.id)[0] return jsonResponse({ "status": "ok", "action": action, "collectionListing": collection.listing_contents(request.user.id), "collection": collection.contents(with_content=True, authenticated=is_member), "sheet": sheet, "sheetListing": sheet_listing, })
def collections_role_api(request, slug, uid, role): """ API for setting a collection members role, or removing them from a collection. """ if request.method != "POST": return jsonResponse({"error": "Unsupported HTTP method."}) collection = Collection().load({"slug": slug}) if not collection: return jsonResponse( {"error": "No collection with slug `{}`.".format(slug)}) uid = int(uid) if request.user.id not in collection.admins: if not (uid == request.user.id and role == "remove"): # non admins can remove themselves return jsonResponse({ "error": "You must be a collection owner to change contributor roles." }) user = UserProfile(id=uid) if not user.exists(): return jsonResponse({"error": "No user with the specified ID exists."}) if role not in ("member", "publisher", "admin", "remove"): return jsonResponse({"error": "Unknown collection contributor role."}) if uid == request.user.id and collection.admins == [request.user.id ] and role != "admin": return jsonResponse({ "error": _("Leaving this collection would leave it without any owners. Please appoint another owner before leaving, or delete the collection." ) }) if role == "remove": collection.remove_member(uid) else: collection.add_member(uid, role) collection_content = collection.contents(with_content=True, authenticated=True) return jsonResponse(collection_content)
def sheet_list_api(request): """ API for listing available sheets """ if request.method == "GET": return jsonResponse(sheet_list(), callback=request.GET.get("callback", None)) # Save a sheet if request.method == "POST": if not request.user.is_authenticated(): return jsonResponse({"error": "You must be logged in to save."}) j = request.POST.get("json") if not j: return jsonResponse({"error": "No JSON given in post data."}) sheet = json.loads(j) #Temp code to throw error in case someone has old sourcesheet code running in browser when backend migration from subsources to indent occurs #Todo remove me by 3/21/16 if "sources" in sheet: if "subsources" in sheet["sources"]: return jsonResponse({ "error": "There's been an error. Please refresh the page." }) if "id" in sheet: existing = get_sheet(sheet["id"]) if "error" not in existing and \ not can_edit(request.user, existing) and \ not can_add(request.user, existing): return jsonResponse( {"error": "You don't have permission to edit this sheet."}) responseSheet = save_sheet(sheet, request.user.id) if "rebuild" in responseSheet and responseSheet["rebuild"]: # Don't bother adding user links if this data won't be used to rebuild the sheet responseSheet["sources"] = annotate_user_links( responseSheet["sources"]) return jsonResponse(responseSheet)
def cache_dump(request): resp = {'ref_cache_dump': model.Ref.cache_dump()} return jsonResponse(resp)
@staff_member_required def cache_dump(request): resp = {'ref_cache_dump': model.Ref.cache_dump()} return jsonResponse(resp) @staff_member_required def export_all(request): start = datetime.now() try: start_export_all() resp = {"status": "ok"} except Exception, e: resp = {"error": str(e)} resp["time"] = (datetime.now() - start).seconds return jsonResponse(resp) @staff_member_required def cause_error(request): resp = {} logger.error(u"This is a simple error") try: erorr = excepting except Exception as e: logger.exception('An Exception has ocurred in the code') erorr = error return jsonResponse(resp) @staff_member_required
def register_api(request): errors, token_dict, _ = process_register_form(request, auth_method='jwt') if len(errors) == 0: return jsonResponse(token_dict) return jsonResponse(errors)
def subscribe(request, email): if subscribe_to_announce(email): return jsonResponse({"status": "ok"}) else: return jsonResponse({"error": "Something went wrong."})
def cache_stats(request): resp = { 'ref_cache_size': model.Ref.cache_size() } return jsonResponse(resp)
def subscribe(request, email): if subscribe_to_announce(email): return jsonResponse({"status": "ok"}) else: return jsonResponse({"error": "Sorry, there was an error."})
def subscribe_educators(request, email): if subscribe_to_list(["Announcements_General", "Announcements_Edu"], email, direct_sign_up=True): return jsonResponse({"status": "ok"}) else: return jsonResponse({"error": "Sorry, there was an error."})
def decorator(request, *args, **kwargs): return jsonResponse(func(request, *args, **kwargs), callback=request.GET.get("callback", None))
def cause_error(request): resp = {} erorr = error return jsonResponse(resp)
def save_sheet_api(request): """ API for listing available sheets """ if request.method == "GET": return jsonResponse({"error": "Unsupported HTTP method."}) # Save a sheet if request.method == "POST": if not request.user.is_authenticated: key = request.POST.get("apikey") if not key: return jsonResponse({"error": "You must be logged in or use an API key to save."}) apikey = db.apikeys.find_one({"key": key}) if not apikey: return jsonResponse({"error": "Unrecognized API key."}) else: apikey = None j = request.POST.get("json") if not j: return jsonResponse({"error": "No JSON given in post data."}) sheet = json.loads(j) if apikey: if "id" in sheet: sheet["lastModified"] = get_sheet(sheet["id"])["dateModified"] # Usually lastModified gets set on the frontend, so we need to set it here to match with the previous dateModified so that the check in `save_sheet` returns properly user = User.objects.get(id=apikey["uid"]) else: user = request.user if "id" in sheet: existing = get_sheet(sheet["id"]) if "error" not in existing and \ not can_edit(user, existing) and \ not can_add(request.user, existing) and \ not can_publish(request.user, existing): return jsonResponse({"error": "You don't have permission to edit this sheet."}) else: existing = None cleaned_sources = [] for source in sheet["sources"]: cleaned_sources.append(clean_source(source)) sheet["sources"] = cleaned_sources sheet["title"] = bleach_text(sheet["title"]) if "summary" in sheet: sheet["summary"] = bleach_text(sheet["summary"]) if sheet.get("group", None): # Quietly enforce group permissions if sheet["group"] not in [g["name"] for g in get_user_groups(user.id)]: # Don't allow non Group members to add a sheet to a group sheet["group"] = None if not can_publish(user, sheet): if not existing: sheet["status"] = "unlisted" else: if existing.get("group", None) != sheet["group"]: # Don't allow non Group publishers to add a new public sheet sheet["status"] = "unlisted" elif existing["status"] != sheet["status"]: # Don't allow non Group publishers from changing status of an existing sheet sheet["status"] = existing["status"] rebuild_nodes = request.POST.get('rebuildNodes', False) responseSheet = save_sheet(sheet, user.id, rebuild_nodes=rebuild_nodes) if "rebuild" in responseSheet and responseSheet["rebuild"]: # Don't bother adding user links if this data won't be used to rebuild the sheet responseSheet["sources"] = annotate_user_links(responseSheet["sources"]) return jsonResponse(responseSheet)
def user_groups_api(request, user_id): if request.method == "GET": is_me = request.user.id == int(user_id) groups_serialized = get_user_groups(int(user_id), is_me) return jsonResponse(groups_serialized) return jsonResponse({"error": "Unsupported HTTP method."})
def user_sheet_list_api_with_sort(request, user_id, sort_by="date", limiter=0, offset=0): limiter = int(limiter) offset = int(offset) private = int(user_id) == request.user.id return jsonResponse(user_sheets(user_id, sort_by, private=private, limit=limiter, skip=offset), callback=request.GET.get("callback", None))
def add_source_to_sheet_api(request, sheet_id): """ API to add a fully formed source (posted as JSON) to sheet_id. The contents of the "source" field will be a dictionary. The input format is similar to, but differs slightly from, the internal format for sources on source sheets. This method reformats the source to the format expected by add_source_to_sheet(). Fields of input dictionary: either `refs` - an array of string refs, indicating a range or `ref` - a string ref or `outsideText` - a string or `outsideBiText` - a dictionary with string fields "he" and "en" or `comment` - a string or `media` - a URL string If the `ref` or `refs` fields are present, the `version`, `he` or `en` fields can further specify the origin or content of text for that ref. """ source = json.loads(request.POST.get("source")) if not source: return jsonResponse({"error": "No source to copy given."}) if "refs" in source and source["refs"]: ref = Ref(source["refs"][0]).to(Ref(source["refs"][-1])) source["ref"] = ref.normal() del source["refs"] if "ref" in source and source["ref"]: ref = Ref(source["ref"]) source["heRef"] = ref.he_normal() if "version" in source or "en" in source or "he" in source: text = {} if "en" in source: text["en"] = source["en"] tc = TextChunk(ref, "he", source["version"]) if source.get("versionLanguage") == "he" else TextChunk(ref, "he") text["he"] = tc.ja().flatten_to_string() del source["en"] elif "he" in source: text["he"] = source["he"] tc = TextChunk(ref, "en", source["version"]) if source.get("versionLanguage") == "en" else TextChunk(ref, "en") text["en"] = tc.ja().flatten_to_string() del source["he"] else: # "version" in source text[source["versionLanguage"]] = TextChunk(ref, source["versionLanguage"], source["version"]).ja().flatten_to_string() other = "he" if source["versionLanguage"] == "en" else "en" text[other] = TextChunk(ref, other).ja().flatten_to_string() source.pop("version", None) source.pop("versionLanguage", None) source["text"] = text else: text = {} tc_eng = TextChunk(ref, "en") tc_heb = TextChunk(ref, "he") if tc_eng: text["en"] = tc_eng.ja().flatten_to_string() if tc_eng.ja().flatten_to_string() != "" else "..." if tc_heb: text["he"] = tc_heb.ja().flatten_to_string() if tc_heb.ja().flatten_to_string() != "" else "..." source["text"] = text note = request.POST.get("note", None) source.pop("node", None) response = add_source_to_sheet(int(sheet_id), source, note=note) return jsonResponse(response)
def update_sheet_tags_api(request, sheet_id): """ API to update tags for sheet_id. """ tags = json.loads(request.POST.get("tags")) return jsonResponse(update_sheet_tags(int(sheet_id), tags))
def sheet_likers_api(request, sheet_id): """ API to retrieve the list of people who like sheet_id. """ response = {"likers": likers_list_for_sheet(sheet_id)} return jsonResponse(response, callback=request.GET.get("callback", None))
def sheets_by_ref_api(request, ref): """ API to get public sheets by ref. """ return jsonResponse(get_sheets_for_ref(ref))