def email_unread_notifications(timeframe):
	"""
	Looks for all unread notifcations and sends each user one email with a summary.
	Marks any sent notifications as "read".

	timeframe may be:
	* 'daily'  - only send to users who have the daily email setting
	* 'weekly' - only send to users who have the weekly email setting
	* 'all'    - send all notifications
	"""

	users = db.notifications.find({"read": False}).distinct("uid")

	for uid in users:
		profile = UserProfile(id=uid)
		if profile.settings["email_notifications"] != timeframe and timeframe != 'all':
			continue
		notifications = NotificationSet().unread_for_user(uid)
		try:
			user = User.objects.get(id=uid)
		except User.DoesNotExist:
			continue

		message_html = render_to_string("email/notifications_email.html", { "notifications": notifications, "recipient": user.first_name })
		#message_text = util.strip_tags(message_html)
		subject      = "New Activity on Sefaria from %s" % notifications.actors_string()
		from_email   = "Sefaria <*****@*****.**>"
		to           = user.email

		msg = EmailMultiAlternatives(subject, message_html, from_email, [to])
		msg.content_subtype = "html"  # Main content is now text/html
		#msg.attach_alternative(message_text, "text/plain")
		msg.send()

		notifications.mark_read(via="email")
def email_unread_notifications(timeframe):
	"""
	Looks for all unread notifications and sends each user one email with a summary.
	Marks any sent notifications as "read".

	timeframe may be:
	* 'daily'  - only send to users who have the daily email setting
	* 'weekly' - only send to users who have the weekly email setting
	* 'all'    - send all notifications
	"""
	from sefaria.model.notification import NotificationSet

	users = db.notifications.find({"read": False, "is_global": False}).distinct("uid")

	for uid in users:
		profile = UserProfile(id=uid)
		if profile.settings["email_notifications"] != timeframe and timeframe != 'all':
			continue
		notifications = NotificationSet().unread_personal_for_user(uid)
		if notifications.count() == 0:
			continue
		try:
			user = User.objects.get(id=uid)
		except User.DoesNotExist:
			continue

		if "interface_language" in profile.settings:
			translation.activate(profile.settings["interface_language"][0:2])

		message_html  = render_to_string("email/notifications_email.html", {"notifications": notifications, "recipient": user.first_name})
		#message_text = util.strip_tags(message_html)
		actors_string = notifications.actors_string()
		verb          = "have" if " and " in actors_string else "has"
		subject       = "%s %s new activity on Sefaria" % (actors_string, verb)
		from_email    = "Sefaria <*****@*****.**>"
		to            = user.email

		msg = EmailMultiAlternatives(subject, message_html, from_email, [to])
		msg.content_subtype = "html"  # Main content is now text/html
		#msg.attach_alternative(message_text, "text/plain")
		msg.send()
		notifications.mark_read(via="email")

		if "interface_language" in profile.settings:
			translation.deactivate()
Exemple #3
0
def save_sheet(sheet, user_id, search_override=False, rebuild_nodes=False):
    """
	Saves sheet to the db, with user_id as owner.
	"""
    def next_sheet_id():
        last_id = db.sheets.find().sort([['id', -1]]).limit(1)
        if last_id.count():
            sheet_id = last_id.next()["id"] + 1
        else:
            sheet_id = 1
        return sheet_id

    sheet["dateModified"] = datetime.now().isoformat()
    status_changed = False
    if "id" in sheet:
        new_sheet = False
        existing = db.sheets.find_one({"id": sheet["id"]})

        if sheet["lastModified"] != existing["dateModified"]:
            # Don't allow saving if the sheet has been modified since the time
            # that the user last received an update
            existing["error"] = "Sheet updated."
            existing["rebuild"] = True
            return existing
        del sheet["lastModified"]
        if sheet["status"] != existing["status"]:
            status_changed = True

        sheet["views"] = existing["views"]  # prevent updating views
        sheet["owner"] = existing["owner"]  # prevent updating owner
        sheet["likes"] = existing["likes"] if "likes" in existing else [
        ]  # prevent updating likes

        existing.update(sheet)
        sheet = existing

    else:
        new_sheet = True
        sheet["dateCreated"] = datetime.now().isoformat()
        if "status" not in sheet:
            sheet["status"] = "unlisted"
        sheet["owner"] = user_id
        sheet["views"] = 1

        #ensure that sheet sources have nodes (primarily for sheets posted via API)
        nextNode = sheet.get("nextNode", 1)
        sheet["nextNode"] = nextNode
        checked_sources = []
        for source in sheet["sources"]:
            if "node" not in source:
                source["node"] = nextNode
                nextNode += 1
            checked_sources.append(source)
        sheet["sources"] = checked_sources

    if status_changed and not new_sheet:
        if sheet["status"] == "public" and "datePublished" not in sheet:
            # PUBLISH
            sheet["datePublished"] = datetime.now().isoformat()
            record_sheet_publication(sheet["id"], user_id)  # record history
            broadcast_sheet_publication(user_id, sheet["id"])
        if sheet["status"] != "public":
            # UNPUBLISH
            delete_sheet_publication(sheet["id"], user_id)  # remove history
            UserStorySet({
                "storyForm": "publishSheet",
                "data.publisher": user_id,
                "data.sheet_id": sheet["id"]
            }).delete()
            NotificationSet({
                "type": "sheet publish",
                "content.publisher_id": user_id,
                "content.sheet_id": sheet["id"]
            }).delete()

    sheet["includedRefs"] = refs_in_sources(sheet.get("sources", []))

    if rebuild_nodes:
        sheet = rebuild_sheet_nodes(sheet)

    if new_sheet:
        # mongo enforces a unique sheet id, get a new id until a unique one has been found
        while True:
            try:
                sheet["id"] = next_sheet_id()
                db.sheets.insert_one(sheet)
                break
            except DuplicateKeyError:
                pass

    else:
        db.sheets.find_one_and_replace({"id": sheet["id"]}, sheet)

    if "tags" in sheet:
        update_sheet_tags(sheet["id"], sheet["tags"])

    if sheet[
            "status"] == "public" and SEARCH_INDEX_ON_SAVE and not search_override:
        try:
            index_name = search.get_new_and_current_index_names(
                "sheet")['current']
            search.index_sheet(index_name, sheet["id"])
        except:
            logger.error(u"Failed index on " + str(sheet["id"]))
    '''
	global last_updated
	last_updated[sheet["id"]] = sheet["dateModified"]
	'''

    return sheet
Exemple #4
0
def save_sheet(sheet, user_id, search_override=False):
    """
	Saves sheet to the db, with user_id as owner.
	"""
    sheet["dateModified"] = datetime.now().isoformat()
    status_changed = False
    if "id" in sheet:
        existing = db.sheets.find_one({"id": sheet["id"]})

        if sheet["lastModified"] != existing["dateModified"]:
            # Don't allow saving if the sheet has been modified since the time
            # that the user last received an update
            existing["error"] = "Sheet updated."
            existing["rebuild"] = True
            return existing
        del sheet["lastModified"]
        if sheet["status"] != existing["status"]:
            status_changed = True

        sheet["views"] = existing["views"]  # prevent updating views
        sheet["owner"] = existing["owner"]  # prevent updating owner
        sheet["likes"] = existing["likes"] if "likes" in existing else [
        ]  # prevent updating likes

        existing.update(sheet)
        sheet = existing

    else:
        sheet["dateCreated"] = datetime.now().isoformat()
        lastId = db.sheets.find().sort([['id', -1]]).limit(1)
        if lastId.count():
            sheet["id"] = lastId.next()["id"] + 1
        else:
            sheet["id"] = 1
        if "status" not in sheet:
            sheet["status"] = "unlisted"
        sheet["owner"] = user_id
        sheet["views"] = 1

    if status_changed:
        if sheet["status"] == "public" and "datePublished" not in sheet:
            # PUBLISH
            sheet["datePublished"] = datetime.now().isoformat()
            record_sheet_publication(sheet["id"], user_id)
            broadcast_sheet_publication(user_id, sheet["id"])
        if sheet["status"] != "public":
            # UNPUBLISH
            delete_sheet_publication(sheet["id"], user_id)
            NotificationSet({
                "type": "sheet publish",
                "content.publisher_id": user_id,
                "content.sheet_id": sheet["id"]
            }).delete()

    db.sheets.update({"id": sheet["id"]}, sheet, True, False)

    if sheet[
            "status"] == "public" and SEARCH_INDEX_ON_SAVE and not search_override:
        index_name = search.get_new_and_current_index_names()['current']
        search.index_sheet(index_name, sheet["id"])

    global last_updated
    last_updated[sheet["id"]] = sheet["dateModified"]

    return sheet
Exemple #5
0
def email_unread_notifications(timeframe):
    """
    Looks for all unread notifications and sends each user one email with a summary.
    Marks any sent notifications as "read".

    timeframe may be:
    * 'daily'  - only send to users who have the daily email setting
    * 'weekly' - only send to users who have the weekly email setting
    * 'all'    - send all notifications
    """
    from sefaria.model.notification import NotificationSet

    detect_potential_spam_message_notifications()

    users = db.notifications.find({
        "read": False,
        "is_global": False
    }).distinct("uid")

    for uid in users:
        profile = UserProfile(id=uid)
        if profile.settings[
                "email_notifications"] != timeframe and timeframe != 'all':
            continue
        notifications = NotificationSet().unread_personal_for_user(uid)
        if len(notifications) == 0:
            continue
        try:
            user = User.objects.get(id=uid)
        except User.DoesNotExist:
            continue

        if "interface_language" in profile.settings:
            translation.activate(profile.settings["interface_language"][0:2])

        message_html = render_to_string("email/notifications_email.html", {
            "notifications": notifications,
            "recipient": user.first_name
        })
        actors_string = notifications.actors_string()
        # TODO Hebrew subjects
        if actors_string:
            verb = "have" if " and " in actors_string else "has"
            subject = "%s %s new activity on Sefaria" % (actors_string, verb)
        elif notifications.like_count() > 0:
            noun = "likes" if notifications.like_count() > 1 else "like"
            subject = "%d new %s on your Source Sheet" % (
                notifications.like_count(), noun)
        from_email = "Sefaria Notifications <*****@*****.**>"
        to = user.email

        msg = EmailMultiAlternatives(subject, message_html, from_email, [to])
        msg.content_subtype = "html"
        try:
            msg.send()
            notifications.mark_read(via="email")
        except AnymailRecipientsRefused:
            print('bad email address: {}'.format(to))

        if "interface_language" in profile.settings:
            translation.deactivate()
Exemple #6
0
 def unread_notification_count(self):
     from sefaria.model.notification import NotificationSet
     return NotificationSet().unread_for_user(self.id).count()
Exemple #7
0
 def recent_notifications(self):
     from sefaria.model.notification import NotificationSet
     return NotificationSet().recent_for_user(self.id)
def unread_notifications_count_for_user(uid):
	"""Returns the number of unread notifications belonging to user uid"""
	# Check for globals to add...
	from sefaria.model.notification import NotificationSet
	return NotificationSet().unread_for_user(uid).count()
Exemple #9
0
def save_sheet(sheet, user_id, search_override=False):
    """
	Saves sheet to the db, with user_id as owner.
	"""
    sheet["dateModified"] = datetime.now().isoformat()
    status_changed = False
    if "id" in sheet:
        existing = db.sheets.find_one({"id": sheet["id"]})

        if sheet["lastModified"] != existing["dateModified"]:
            # Don't allow saving if the sheet has been modified since the time
            # that the user last received an update
            existing["error"] = "Sheet updated."
            existing["rebuild"] = True
            return existing
        del sheet["lastModified"]
        if sheet["status"] != existing["status"]:
            status_changed = True

        sheet["views"] = existing["views"]  # prevent updating views
        sheet["owner"] = existing["owner"]  # prevent updating owner
        sheet["likes"] = existing["likes"] if "likes" in existing else [
        ]  # prevent updating likes

        existing.update(sheet)
        sheet = existing

    else:
        sheet["dateCreated"] = datetime.now().isoformat()
        lastId = db.sheets.find().sort([['id', -1]]).limit(1)
        if lastId.count():
            sheet["id"] = lastId.next()["id"] + 1
        else:
            sheet["id"] = 1
        if "status" not in sheet:
            sheet["status"] = "unlisted"
        sheet["owner"] = user_id
        sheet["views"] = 1

        #ensure that sheet sources have nodes (primarily for sheets posted via API)
        nextNode = sheet.get("nextNode", 1)
        sheet["nextNode"] = nextNode
        checked_sources = []
        for source in sheet["sources"]:
            if "node" not in source:
                source["node"] = nextNode
                nextNode += 1
            checked_sources.append(source)
        sheet["sources"] = checked_sources

    if status_changed:
        if sheet["status"] == "public" and "datePublished" not in sheet:
            # PUBLISH
            sheet["datePublished"] = datetime.now().isoformat()
            record_sheet_publication(sheet["id"], user_id)
            broadcast_sheet_publication(user_id, sheet["id"])
        if sheet["status"] != "public":
            # UNPUBLISH
            delete_sheet_publication(sheet["id"], user_id)
            NotificationSet({
                "type": "sheet publish",
                "content.publisher_id": user_id,
                "content.sheet_id": sheet["id"]
            }).delete()

    db.sheets.update({"id": sheet["id"]}, sheet, True, False)

    if "tags" in sheet:
        update_sheet_tags(sheet["id"], sheet["tags"])

    if sheet[
            "status"] == "public" and SEARCH_INDEX_ON_SAVE and not search_override:
        try:
            index_name = search.get_new_and_current_index_names(
                "sheet")['current']
            search.index_sheet(index_name, sheet["id"])
        except:
            logger.error("Failed index on " + str(sheet["id"]))
    '''
	global last_updated
	last_updated[sheet["id"]] = sheet["dateModified"]
	'''

    return sheet
Exemple #10
0
def save_sheet(sheet, user_id, search_override=False, rebuild_nodes=False):
    """
	Saves sheet to the db, with user_id as owner.
	"""
    def next_sheet_id():
        last_id = db.sheets.find().sort([['id', -1]]).limit(1)
        if last_id.count():
            sheet_id = last_id.next()["id"] + 1
        else:
            sheet_id = 1
        return sheet_id

    sheet["dateModified"] = datetime.now().isoformat()
    status_changed = False
    if "id" in sheet:
        new_sheet = False
        existing = db.sheets.find_one({"id": sheet["id"]})

        if sheet["lastModified"] != existing["dateModified"]:
            # Don't allow saving if the sheet has been modified since the time
            # that the user last received an update
            existing["error"] = "Sheet updated."
            existing["rebuild"] = True
            return existing
        del sheet["lastModified"]
        if sheet["status"] != existing["status"]:
            status_changed = True

        old_topics = existing.get("topics", [])
        topics_diff = topic_list_diff(old_topics, sheet.get("topics", []))

        # Protected fields -- can't be set from outside
        sheet["views"] = existing["views"]
        sheet["owner"] = existing["owner"]
        sheet["likes"] = existing["likes"] if "likes" in existing else []
        if "noindex" in existing:
            sheet["noindex"] = existing["noindex"]

        existing.update(sheet)
        sheet = existing

    else:
        new_sheet = True
        sheet["dateCreated"] = datetime.now().isoformat()
        if "status" not in sheet:
            sheet["status"] = "unlisted"
        sheet["owner"] = user_id
        sheet["views"] = 1

        old_topics = []
        topics_diff = topic_list_diff(old_topics, sheet.get("topics", []))

        #ensure that sheet sources have nodes (primarily for sheets posted via API)
        nextNode = sheet.get("nextNode", 1)
        sheet["nextNode"] = nextNode
        checked_sources = []
        for source in sheet["sources"]:
            if "node" not in source:
                source["node"] = nextNode
                nextNode += 1
            checked_sources.append(source)
        sheet["sources"] = checked_sources

    if status_changed and not new_sheet:
        if sheet["status"] == "public" and "datePublished" not in sheet:
            # PUBLISH
            sheet["datePublished"] = datetime.now().isoformat()
            record_sheet_publication(sheet["id"], user_id)  # record history
            broadcast_sheet_publication(user_id, sheet["id"])
        if sheet["status"] != "public":
            # UNPUBLISH
            delete_sheet_publication(sheet["id"], user_id)  # remove history
            UserStorySet({
                "storyForm": "publishSheet",
                "uid": user_id,
                "data.publisher": user_id,
                "data.sheet_id": sheet["id"]
            }).delete()
            NotificationSet({
                "type": "sheet publish",
                "uid": user_id,
                "content.publisher_id": user_id,
                "content.sheet_id": sheet["id"]
            }).delete()

    sheet["includedRefs"] = refs_in_sources(sheet.get("sources", []))
    sheet["expandedRefs"] = model.Ref.expand_refs(sheet["includedRefs"])
    sheet["sheetLanguage"] = get_sheet_language(sheet)

    if rebuild_nodes:
        sheet = rebuild_sheet_nodes(sheet)

    if new_sheet:
        # mongo enforces a unique sheet id, get a new id until a unique one has been found
        while True:
            try:
                sheet["id"] = next_sheet_id()
                db.sheets.insert_one(sheet)
                break
            except DuplicateKeyError:
                pass

    else:
        db.sheets.find_one_and_replace({"id": sheet["id"]}, sheet)

    if len(topics_diff["added"]) or len(topics_diff["removed"]):
        update_sheet_topics(sheet["id"], sheet.get("topics", []), old_topics)
        sheet = db.sheets.find_one({"id": sheet["id"]})

    if status_changed and sheet["status"] == "public":
        # Publish, update sheet topic links as though all are new - add links for all
        update_sheet_topic_links(sheet["id"], sheet["topics"], [])
    elif status_changed and sheet["status"] != "public":
        # Unpublish, update sheet topic links as though there are now none - remove links for all
        update_sheet_topic_links(sheet["id"], [], old_topics)

    if sheet[
            "status"] == "public" and SEARCH_INDEX_ON_SAVE and not search_override:
        try:
            index_name = search.get_new_and_current_index_names(
                "sheet")['current']
            search.index_sheet(index_name, sheet["id"])
        except:
            logger.error("Failed index on " + str(sheet["id"]))

    return sheet