예제 #1
0
def frienduser_(request):
    if not define.is_vouched_for(request.userid):
        raise WeasylError("vouchRequired")

    form = request.web_input(userid="")
    otherid = define.get_int(form.userid)

    if request.userid == otherid:
        raise WeasylError('cannotSelfFriend')

    if form.action == "sendfriendrequest":
        if not frienduser.check(request.userid,
                                otherid) and not frienduser.already_pending(
                                    request.userid, otherid):
            frienduser.request(request.userid, otherid)
    elif form.action == "withdrawfriendrequest":
        if frienduser.already_pending(request.userid, otherid):
            frienduser.remove_request(request.userid, otherid)
    elif form.action == "unfriend":
        frienduser.remove(request.userid, otherid)

    if form.feature == "pending":
        raise HTTPSeeOther(location="/manage/friends?feature=pending")
    else:  # typical value will be user
        raise HTTPSeeOther(
            location="/~%s" %
            (define.get_sysname(define.get_display_name(otherid))))
예제 #2
0
def select_list(userid, rating, limit, otherid):
    statement = [
        "SELECT jo.journalid, jo.title, jo.unixtime, jo.content FROM journal jo WHERE"
    ]

    if userid:
        # filter own content in SFW mode
        if d.is_sfw_mode():
            statement.append(" (jo.rating <= %i)" % (rating, ))
        else:
            statement.append(" (jo.userid = %i OR jo.rating <= %i)" %
                             (userid, rating))
        statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid))
    else:
        statement.append(" jo.rating <= %i" % (rating, ))

    statement.append(
        " AND jo.userid = %i AND jo.settings !~ '[%sh]'" %
        (otherid, "" if frienduser.check(userid, otherid) else "f"))

    statement.append("ORDER BY jo.journalid DESC LIMIT %i" % limit)

    return [{
        "journalid": i[0],
        "title": i[1],
        "created_at": arrow.get(i[2] - UNIXTIME_OFFSET),
        "content": i[3],
    } for i in d.execute("".join(statement))]
예제 #3
0
def frienduser_(request):
    form = request.web_input(userid="")
    otherid = define.get_int(form.userid)

    if request.userid == otherid:
        return Response(
            define.errorpage(request.userid, "You cannot friend yourself."))

    if form.action == "sendfriendrequest":
        if not frienduser.check(request.userid,
                                otherid) and not frienduser.already_pending(
                                    request.userid, otherid):
            frienduser.request(request.userid, otherid)
    elif form.action == "withdrawfriendrequest":
        if frienduser.already_pending(request.userid, otherid):
            frienduser.remove_request(request.userid, otherid)
    elif form.action == "unfriend":
        frienduser.remove(request.userid, otherid)

    if form.feature == "pending":
        raise HTTPSeeOther(location="/manage/friends?feature=pending")
    else:  # typical value will be user
        raise HTTPSeeOther(
            location="/~%s" %
            (define.get_sysname(define.get_display_name(otherid))))
예제 #4
0
파일: journal.py 프로젝트: Syfaro/weasyl
def select_list(userid, rating, limit, otherid=None, backid=None, nextid=None, config=None):
    if config is None:
        config = d.get_config(userid)

    statement = ["SELECT jo.journalid, jo.title, jo.unixtime FROM journal jo WHERE"]

    if userid:
        # filter own content in SFW mode
        if d.is_sfw_mode():
            statement.append(" (jo.rating <= %i)" % (rating,))
        else:
            statement.append(" (jo.userid = %i OR jo.rating <= %i)" % (userid, rating))
        if not otherid:
            statement.append(m.MACRO_IGNOREUSER % (userid, "jo"))
        statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid))
    else:
        statement.append(" jo.rating <= %i" % (rating,))

    if otherid:
        statement.append(
            " AND jo.userid = %i AND jo.settings !~ '[%sh]'" % (otherid, "" if frienduser.check(userid, otherid) else "f"))
    else:
        statement.append(" AND jo.settings !~ 'h'")

    statement.append("ORDER BY jo.journalid DESC LIMIT %i" % limit)

    query = [{
        "journalid": i[0],
        "title": i[1],
        "unixtime": i[2],
    } for i in d.execute("".join(statement))]

    return query[::-1] if backid else query
예제 #5
0
파일: journal.py 프로젝트: Syfaro/weasyl
def select_latest(userid, rating, otherid=None, config=None):
    if config is None:
        config = d.get_config(userid)

    statement = ["SELECT jo.journalid, jo.title, jo.content, jo.unixtime FROM journal jo WHERE"]

    if userid:
        if d.is_sfw_mode():
            statement.append(" (jo.rating <= %i)" % (rating,))
        else:
            statement.append(" (jo.userid = %i OR jo.rating <= %i)" % (userid, rating))
        if not otherid:
            statement.append(m.MACRO_IGNOREUSER % (userid, "jo"))
        statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid))
    else:
        statement.append(" jo.rating <= %i" % (rating,))

    if otherid:
        statement.append(
            " AND jo.userid = %i AND jo.settings !~ '[%sh]'" % (otherid, "" if frienduser.check(userid, otherid) else "f"))

    statement.append("ORDER BY jo.journalid DESC LIMIT 1")
    query = d.execute("".join(statement), options="single")

    if query:
        return {
            "journalid": query[0],
            "title": query[1],
            "content": query[2],
            "unixtime": query[3],
            "comments": d.execute("SELECT COUNT(*) FROM journalcomment WHERE targetid = %i AND settings !~ 'h'",
                                  [query[0]], ["element"]),
        }
예제 #6
0
def select_latest(userid, rating, otherid):
    statement = ["SELECT jo.journalid, jo.title, jo.content, jo.unixtime FROM journal jo WHERE"]

    if userid:
        if d.is_sfw_mode():
            statement.append(" (jo.rating <= %i)" % (rating,))
        else:
            statement.append(" (jo.userid = %i OR jo.rating <= %i)" % (userid, rating))
        statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid))
    else:
        statement.append(" jo.rating <= %i" % (rating,))

    statement.append(
        " AND jo.userid = %i AND jo.settings !~ '[%sh]'" % (otherid, "" if frienduser.check(userid, otherid) else "f"))

    statement.append("ORDER BY jo.journalid DESC LIMIT 1")
    query = d.engine.execute("".join(statement)).first()

    if query:
        return {
            "journalid": query[0],
            "title": query[1],
            "content": query[2],
            "unixtime": query[3],
            "comments": d.engine.scalar(
                "SELECT count(*) FROM journalcomment WHERE targetid = %(journal)s AND settings !~ 'h'",
                journal=query[0],
            ),
        }
예제 #7
0
파일: shout.py 프로젝트: amanyashu/weasyl
def insert(userid, target_user, parentid, content, staffnotes):
    # Check invalid content
    if not content:
        raise WeasylError("commentInvalid")
    elif not target_user or not d.is_vouched_for(target_user):
        raise WeasylError("Unexpected")

    # Determine parent userid
    if parentid:
        parentuserid = d.engine.scalar(
            "SELECT userid FROM comments WHERE commentid = %(parent)s",
            parent=parentid,
        )

        if parentuserid is None:
            raise WeasylError("shoutRecordMissing")
    else:
        parentuserid = None

    # Check permissions
    if userid not in staff.MODS:
        if ignoreuser.check(target_user, userid):
            raise WeasylError("pageOwnerIgnoredYou")
        elif ignoreuser.check(userid, target_user):
            raise WeasylError("youIgnoredPageOwner")
        elif ignoreuser.check(parentuserid, userid):
            raise WeasylError("replyRecipientIgnoredYou")
        elif ignoreuser.check(userid, parentuserid):
            raise WeasylError("youIgnoredReplyRecipient")

        _, is_banned, _ = d.get_login_settings(target_user)
        profile_config = d.get_config(target_user)

        if is_banned or "w" in profile_config or "x" in profile_config and not frienduser.check(
                userid, target_user):
            raise WeasylError("insufficientActionPermissions")

    # Create comment
    settings = 's' if staffnotes else ''
    co = d.meta.tables['comments']
    db = d.connect()
    commentid = db.scalar(co.insert().values(userid=userid,
                                             target_user=target_user,
                                             parentid=parentid or None,
                                             content=content,
                                             unixtime=arrow.utcnow(),
                                             settings=settings).returning(
                                                 co.c.commentid))

    # Create notification
    if parentid and userid != parentuserid:
        if not staffnotes or parentuserid in staff.MODS:
            welcome.shoutreply_insert(userid, commentid, parentuserid,
                                      parentid, staffnotes)
    elif not staffnotes and target_user and userid != target_user:
        welcome.shout_insert(userid, commentid, otherid=target_user)

    d.metric('increment', 'shouts')

    return commentid
예제 #8
0
파일: journal.py 프로젝트: Locynaeh/weasyl
def select_list(userid, rating, limit, otherid=None, backid=None, nextid=None):
    statement = ["SELECT jo.journalid, jo.title, jo.unixtime FROM journal jo WHERE"]

    if userid:
        # filter own content in SFW mode
        if d.is_sfw_mode():
            statement.append(" (jo.rating <= %i)" % (rating,))
        else:
            statement.append(" (jo.userid = %i OR jo.rating <= %i)" % (userid, rating))
        if not otherid:
            statement.append(m.MACRO_IGNOREUSER % (userid, "jo"))
        statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid))
    else:
        statement.append(" jo.rating <= %i" % (rating,))

    if otherid:
        statement.append(
            " AND jo.userid = %i AND jo.settings !~ '[%sh]'" % (otherid, "" if frienduser.check(userid, otherid) else "f"))
    else:
        statement.append(" AND jo.settings !~ 'h'")

    statement.append("ORDER BY jo.journalid DESC LIMIT %i" % limit)

    query = [{
        "journalid": i[0],
        "title": i[1],
        "unixtime": i[2],
    } for i in d.execute("".join(statement))]

    return query[::-1] if backid else query
예제 #9
0
파일: shout.py 프로젝트: greysteil/wzl-test
def insert(userid, shout, staffnotes=False):
    # Check invalid content
    if not shout.content:
        raise WeasylError("commentInvalid")
    elif not shout.userid:
        raise WeasylError("Unexpected")

    # Determine indent and parentuserid
    if shout.parentid:
        query = d.execute("SELECT userid, indent FROM comments WHERE commentid = %i",
                          [shout.parentid], options="single")

        if not query:
            raise WeasylError("shoutRecordMissing")

        indent, parentuserid = query[1] + 1, query[0]
    else:
        indent, parentuserid = 0, None

    # Check permissions
    if userid not in staff.MODS:
        if ignoreuser.check(shout.userid, userid):
            raise WeasylError("pageOwnerIgnoredYou")
        elif ignoreuser.check(userid, shout.userid):
            raise WeasylError("youIgnoredPageOwner")
        elif ignoreuser.check(parentuserid, userid):
            raise WeasylError("replyRecipientIgnoredYou")
        elif ignoreuser.check(userid, parentuserid):
            raise WeasylError("youIgnoredReplyRecipient")

        settings = d.execute("SELECT lo.settings, pr.config FROM login lo"
                             " INNER JOIN profile pr ON lo.userid = pr.userid"
                             " WHERE lo.userid = %i", [shout.userid], options="single")

        if "b" in settings[0] or "w" in settings[1] or "x" in settings[1] and not frienduser.check(userid, shout.userid):
            raise WeasylError("insufficientActionPermissions")

    # Create comment
    settings = 's' if staffnotes else ''
    co = d.meta.tables['comments']
    db = d.connect()
    commentid = db.scalar(
        co.insert()
        .values(userid=userid, target_user=shout.userid, parentid=shout.parentid or None, content=shout.content,
                unixtime=arrow.utcnow(), indent=indent, settings=settings)
        .returning(co.c.commentid))

    # Create notification
    if shout.parentid and userid != parentuserid:
        if not staffnotes or parentuserid in staff.MODS:
            welcome.shoutreply_insert(userid, commentid, parentuserid, shout.parentid, staffnotes)
    elif not staffnotes and shout.userid and userid != shout.userid:
        welcome.shout_insert(userid, commentid, otherid=shout.userid)

    d.metric('increment', 'shouts')

    return commentid
예제 #10
0
파일: shout.py 프로젝트: charmander/weasyl
def insert(userid, shout, staffnotes=False):
    # Check invalid content
    if not shout.content:
        raise WeasylError("commentInvalid")
    elif not shout.userid:
        raise WeasylError("Unexpected")

    # Determine indent and parentuserid
    if shout.parentid:
        query = d.execute("SELECT userid, indent FROM comments WHERE commentid = %i",
                          [shout.parentid], options="single")

        if not query:
            raise WeasylError("shoutRecordMissing")

        indent, parentuserid = query[1] + 1, query[0]
    else:
        indent, parentuserid = 0, None

    # Check permissions
    if userid not in staff.MODS:
        if ignoreuser.check(shout.userid, userid):
            raise WeasylError("pageOwnerIgnoredYou")
        elif ignoreuser.check(userid, shout.userid):
            raise WeasylError("youIgnoredPageOwner")
        elif ignoreuser.check(parentuserid, userid):
            raise WeasylError("replyRecipientIgnoredYou")
        elif ignoreuser.check(userid, parentuserid):
            raise WeasylError("youIgnoredReplyRecipient")

        settings = d.execute("SELECT lo.settings, pr.config FROM login lo"
                             " INNER JOIN profile pr ON lo.userid = pr.userid"
                             " WHERE lo.userid = %i", [shout.userid], options="single")

        if "b" in settings[0] or "w" in settings[1] or "x" in settings[1] and not frienduser.check(userid, shout.userid):
            raise WeasylError("insufficientActionPermissions")

    # Create comment
    settings = 's' if staffnotes else ''
    co = d.meta.tables['comments']
    db = d.connect()
    commentid = db.scalar(
        co.insert()
        .values(userid=userid, target_user=shout.userid, parentid=shout.parentid or None, content=shout.content,
                unixtime=arrow.utcnow(), indent=indent, settings=settings)
        .returning(co.c.commentid))

    # Create notification
    if shout.parentid and userid != parentuserid:
        if not staffnotes or parentuserid in staff.MODS:
            welcome.shoutreply_insert(userid, commentid, parentuserid, shout.parentid, staffnotes)
    elif not staffnotes and shout.userid and userid != shout.userid:
        welcome.shout_insert(userid, commentid, otherid=shout.userid)

    d.metric('increment', 'shouts')

    return commentid
예제 #11
0
def insert(userid, submitid=None, charid=None, journalid=None):
    if submitid:
        content_table, id_field, target = "submission", "submitid", submitid
    elif charid:
        content_table, id_field, target = "character", "charid", charid
    else:
        content_table, id_field, target = "journal", "journalid", journalid

    query = d.execute("SELECT userid, settings FROM %s WHERE %s = %i",
                      [content_table, id_field, target],
                      options="single")

    if not query:
        raise WeasylError("TargetRecordMissing")
    elif userid == query[0]:
        raise WeasylError("CannotSelfFavorite")
    elif "f" in query[1] and not frienduser.check(userid, query[0]):
        raise WeasylError("FriendsOnly")
    elif ignoreuser.check(userid, query[0]):
        raise WeasylError("YouIgnored")
    elif ignoreuser.check(query[0], userid):
        raise WeasylError("contentOwnerIgnoredYou")

    insert_result = d.engine.execute(
        'INSERT INTO favorite (userid, targetid, type, unixtime) '
        'VALUES (%(user)s, %(target)s, %(type)s, %(now)s) '
        'ON CONFLICT DO NOTHING',
        user=userid,
        target=d.get_targetid(submitid, charid, journalid),
        type='s' if submitid else 'f' if charid else 'j',
        now=d.get_time())

    if insert_result.rowcount == 0:
        return

    # create a list of users to notify
    notified = set(collection.find_owners(submitid))

    # conditions under which "other" should be notified
    def can_notify(other):
        other_jsonb = d.get_profile_settings(other)
        allow_notify = other_jsonb.allow_collection_notifs
        not_ignored = not ignoreuser.check(other, userid)
        return allow_notify and not_ignored

    notified = set(filter(can_notify, notified))
    # always notify for own content
    notified.add(query[0])

    for other in notified:
        welcome.favorite_insert(userid,
                                submitid=submitid,
                                charid=charid,
                                journalid=journalid,
                                otherid=other)
예제 #12
0
def select_view_api(userid, submitid, anyway=False, increment_views=False):
    rating = d.get_rating(userid)
    db = d.connect()
    sub = db.query(orm.Submission).get(submitid)
    if sub is None or 'hidden' in sub.settings:
        raise WeasylError("submissionRecordMissing")
    sub_rating = sub.rating.code
    if 'friends-only' in sub.settings and not frienduser.check(userid, sub.userid):
        raise WeasylError("submissionRecordMissing")
    elif sub_rating > rating and userid != sub.userid:
        raise WeasylError("RatingExceeded")
    elif not anyway and ignoreuser.check(userid, sub.userid):
        raise WeasylError("UserIgnored")
    elif not anyway and blocktag.check(userid, submitid=submitid):
        raise WeasylError("TagBlocked")

    description = sub.content
    embedlink = None
    if 'embedded-content' in sub.settings:
        embedlink, _, description = description.partition('\n')
    elif 'gdocs-embed' in sub.settings:
        embedlink = sub.google_doc_embed.embed_url

    views = sub.page_views
    if increment_views and d.common_view_content(userid, submitid, 'submit'):
        views += 1

    return {
        'submitid': submitid,
        'title': sub.title,
        'owner': sub.owner.profile.username,
        'owner_login': sub.owner.login_name,
        'owner_media': api.tidy_all_media(media.get_user_media(sub.userid)),
        'media': api.tidy_all_media(media.get_submission_media(submitid)),
        'description': text.markdown(description),
        'embedlink': embedlink,
        'folderid': sub.folderid,
        'folder_name': sub.folder.title if sub.folderid else None,
        'posted_at': d.iso8601(sub.unixtime),
        'tags': searchtag.select(submitid=submitid),
        'link': d.absolutify_url("/submission/%d/%s" % (submitid, text.slug_for(sub.title))),

        'type': 'submission',
        'subtype': m.CATEGORY_PARSABLE_MAP[sub.subtype // 1000 * 1000],
        'rating': sub.rating.name,

        'views': views,
        'favorites': favorite.count(submitid),
        'comments': comment.count(submitid),
        'favorited': favorite.check(userid, submitid=submitid),
        'friends_only': 'friends-only' in sub.settings,
    }
예제 #13
0
파일: submission.py 프로젝트: Syfaro/weasyl
def select_view_api(userid, submitid, anyway=False, increment_views=False):
    rating = d.get_rating(userid)
    db = d.connect()
    sub = db.query(orm.Submission).get(submitid)
    if sub is None or 'hidden' in sub.settings:
        raise WeasylError("submissionRecordMissing")
    sub_rating = sub.rating.code
    if 'friends-only' in sub.settings and not frienduser.check(userid, sub.userid):
        raise WeasylError("submissionRecordMissing")
    elif sub_rating > rating and userid != sub.userid:
        raise WeasylError("RatingExceeded")
    elif not anyway and ignoreuser.check(userid, sub.userid):
        raise WeasylError("UserIgnored")
    elif not anyway and blocktag.check(userid, submitid=submitid):
        raise WeasylError("TagBlocked")

    description = sub.content
    embedlink = None
    if 'embedded-content' in sub.settings:
        embedlink, _, description = description.partition('\n')
    elif 'gdocs-embed' in sub.settings:
        embedlink = sub.google_doc_embed.embed_url

    views = sub.page_views
    if increment_views and d.common_view_content(userid, submitid, 'submit'):
        views += 1

    return {
        'submitid': submitid,
        'title': sub.title,
        'owner': sub.owner.profile.username,
        'owner_login': sub.owner.login_name,
        'owner_media': api.tidy_all_media(media.get_user_media(sub.userid)),
        'media': api.tidy_all_media(media.get_submission_media(submitid)),
        'description': text.markdown(description),
        'embedlink': embedlink,
        'folderid': sub.folderid,
        'folder_name': sub.folder.title if sub.folderid else None,
        'posted_at': d.iso8601(sub.unixtime),
        'tags': searchtag.select(submitid=submitid),
        'link': d.absolutify_url("/submission/%d/%s" % (submitid, text.slug_for(sub.title))),

        'type': 'submission',
        'subtype': m.CATEGORY_PARSABLE_MAP[sub.subtype // 1000 * 1000],
        'rating': sub.rating.name,

        'views': views,
        'favorites': favorite.count(submitid),
        'comments': comment.count(submitid),
        'favorited': favorite.check(userid, submitid=submitid),
        'friends_only': 'friends-only' in sub.settings,
    }
예제 #14
0
def _select_journal_and_check(userid,
                              journalid,
                              rating=None,
                              ignore=True,
                              anyway=False,
                              increment_views=True):
    """Selects a journal, after checking if the user is authorized, etc.

    Args:
        userid (int): Currently authenticating user ID.
        journalid (int): Character ID to fetch.
        rating (int): Maximum rating to display. Defaults to None.
        ignore (bool): Whether to respect ignored or blocked tags. Defaults to True.
        anyway (bool): Whether ignore checks and display anyway. Defaults to False.
        increment_views (bool): Whether to increment the number of views on the submission. Defaults to True.

    Returns:
        A journal and all needed data as a dict.
    """

    query = d.engine.execute("""
        SELECT jo.userid, pr.username, jo.unixtime, jo.title, jo.content, jo.rating, jo.settings, jo.page_views, pr.config
        FROM journal jo JOIN profile pr ON jo.userid = pr.userid
        WHERE jo.journalid = %(id)s
    """,
                             id=journalid).first()

    if not query:
        # If there's no query result, there's no record, so fast-fail.
        raise WeasylError('journalRecordMissing')
    elif journalid and userid in staff.MODS and anyway:
        pass
    elif not query or 'h' in query.settings:
        raise WeasylError('journalRecordMissing')
    elif query.rating > rating and (
        (userid != query.userid and userid not in staff.MODS)
            or d.is_sfw_mode()):
        raise WeasylError('RatingExceeded')
    elif 'f' in query.settings and not frienduser.check(userid, query.userid):
        raise WeasylError('FriendsOnly')
    elif ignore and ignoreuser.check(userid, query.userid):
        raise WeasylError('UserIgnored')
    elif ignore and blocktag.check(userid, journalid=journalid):
        raise WeasylError('TagBlocked')

    query = dict(query)

    if increment_views and d.common_view_content(userid, journalid, 'journal'):
        query['page_views'] += 1

    return query
예제 #15
0
def _select_character_and_check(userid,
                                charid,
                                rating=None,
                                ignore=True,
                                anyway=False,
                                increment_views=True):
    """Selects a character, after checking if the user is authorized, etc.

    Args:
        userid (int): Currently authenticating user ID.
        charid (int): Character ID to fetch.
        rating (int): Maximum rating to display. Defaults to None.
        ignore (bool): Whether to respect ignored or blocked tags. Defaults to True.
        anyway (bool): Whether to ignore checks and display anyway. Defaults to False.
        increment_views (bool): Whether to increment the number of views on the submission. Defaults to True.

    Returns:
        A character and all needed data as a dict.
    """

    query = define.engine.execute("""
        SELECT
            ch.userid, pr.username, ch.unixtime, ch.char_name, ch.age, ch.gender, ch.height, ch.weight, ch.species,
            ch.content, ch.rating, ch.settings, ch.page_views, pr.config
        FROM character ch
            INNER JOIN profile pr USING (userid)
        WHERE ch.charid = %(charid)s
    """,
                                  charid=charid).first()

    if query and userid in staff.MODS and anyway:
        pass
    elif not query or 'h' in query.settings:
        raise WeasylError('characterRecordMissing')
    elif query.rating > rating and (
        (userid != query.userid and userid not in staff.MODS)
            or define.is_sfw_mode()):
        raise WeasylError('RatingExceeded')
    elif 'f' in query.settings and not frienduser.check(userid, query.userid):
        raise WeasylError('FriendsOnly')
    elif ignore and ignoreuser.check(userid, query.userid):
        raise WeasylError('UserIgnored')
    elif ignore and blocktag.check(userid, charid=charid):
        raise WeasylError('TagBlocked')

    query = dict(query)

    if increment_views and define.common_view_content(userid, charid, 'char'):
        query['page_views'] += 1

    return query
예제 #16
0
파일: favorite.py 프로젝트: Syfaro/weasyl
def insert(userid, submitid=None, charid=None, journalid=None):
    if submitid:
        content_table, id_field, target = "submission", "submitid", submitid
    elif charid:
        content_table, id_field, target = "character", "charid", charid
    else:
        content_table, id_field, target = "journal", "journalid", journalid

    query = d.execute("SELECT userid, settings FROM %s WHERE %s = %i",
                      [content_table, id_field, target], options="single")

    if not query:
        raise WeasylError("TargetRecordMissing")
    elif userid == query[0]:
        raise WeasylError("CannotSelfFavorite")
    elif "f" in query[1] and not frienduser.check(userid, query[0]):
        raise WeasylError("FriendsOnly")
    elif ignoreuser.check(userid, query[0]):
        raise WeasylError("YouIgnored")
    elif ignoreuser.check(query[0], userid):
        raise WeasylError("contentOwnerIgnoredYou")

    insert_result = d.engine.execute(
        'INSERT INTO favorite (userid, targetid, type, unixtime) '
        'VALUES (%(user)s, %(target)s, %(type)s, %(now)s) '
        'ON CONFLICT DO NOTHING',
        user=userid,
        target=d.get_targetid(submitid, charid, journalid),
        type='s' if submitid else 'f' if charid else 'j',
        now=d.get_time())

    if insert_result.rowcount == 0:
        return

    # create a list of users to notify
    notified = set(collection.find_owners(submitid))

    # conditions under which "other" should be notified
    def can_notify(other):
        other_jsonb = d.get_profile_settings(other)
        allow_notify = other_jsonb.allow_collection_notifs
        not_ignored = not ignoreuser.check(other, userid)
        return allow_notify and not_ignored
    notified = set(filter(can_notify, notified))
    # always notify for own content
    notified.add(query[0])

    for other in notified:
        welcome.favorite_insert(userid, submitid=submitid, charid=charid, journalid=journalid, otherid=other)
예제 #17
0
파일: journal.py 프로젝트: taedixon/weasyl
def select_latest(userid, rating, otherid=None, config=None):
    if config is None:
        config = d.get_config(userid)

    statement = [
        "SELECT jo.journalid, jo.title, jo.unixtime FROM journal jo WHERE"
    ]

    if userid:
        if d.is_sfw_mode():
            statement.append(" (jo.rating <= %i)" % (rating, ))
        else:
            statement.append(" (jo.userid = %i OR jo.rating <= %i)" %
                             (userid, rating))
        if not otherid:
            statement.append(m.MACRO_IGNOREUSER % (userid, "jo"))
        statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid))
    else:
        statement.append(" jo.rating <= %i" % (rating, ))

    if otherid:
        statement.append(
            " AND jo.userid = %i AND jo.settings !~ '[%sh]'" %
            (otherid, "" if frienduser.check(userid, otherid) else "f"))

    statement.append("ORDER BY jo.journalid DESC LIMIT 1")
    query = d.execute("".join(statement), options="single")

    if query:
        return {
            "journalid":
            query[0],
            "title":
            query[1],
            "unixtime":
            query[2],
            "content":
            files.read("%s%s%i.txt" % (m.MACRO_SYS_JOURNAL_PATH,
                                       d.get_hash_path(query[0]), query[0])),
            "comments":
            d.execute(
                "SELECT COUNT(*) FROM journalcomment WHERE targetid = %i AND settings !~ 'h'",
                [query[0]], ["element"]),
        }
예제 #18
0
def _select_character_and_check(userid, charid, rating=None, ignore=True, anyway=False, increment_views=True):
    """Selects a character, after checking if the user is authorized, etc.

    Args:
        userid (int): Currently authenticating user ID.
        charid (int): Character ID to fetch.
        rating (int): Maximum rating to display. Defaults to None.
        ignore (bool): Whether to respect ignored or blocked tags. Defaults to True.
        anyway (bool): Whether to ignore checks and display anyway. Defaults to False.
        increment_views (bool): Whether to increment the number of views on the submission. Defaults to True.

    Returns:
        A character and all needed data as a dict.
    """

    query = define.engine.execute("""
        SELECT
            ch.userid, pr.username, ch.unixtime, ch.char_name, ch.age, ch.gender, ch.height, ch.weight, ch.species,
            ch.content, ch.rating, ch.settings, ch.page_views, pr.config
        FROM character ch
            INNER JOIN profile pr USING (userid)
        WHERE ch.charid = %(charid)s
    """, charid=charid).first()

    if query and userid in staff.MODS and anyway:
        pass
    elif not query or 'h' in query.settings:
        raise WeasylError('characterRecordMissing')
    elif query.rating > rating and ((userid != query.userid and userid not in staff.MODS) or define.is_sfw_mode()):
        raise WeasylError('RatingExceeded')
    elif 'f' in query.settings and not frienduser.check(userid, query.userid):
        raise WeasylError('FriendsOnly')
    elif ignore and ignoreuser.check(userid, query.userid):
        raise WeasylError('UserIgnored')
    elif ignore and blocktag.check(userid, charid=charid):
        raise WeasylError('TagBlocked')

    query = dict(query)

    if increment_views and define.common_view_content(userid, charid, 'char'):
        query['page_views'] += 1

    return query
예제 #19
0
def frienduser_(request):
    form = request.web_input(userid="")
    otherid = define.get_int(form.userid)

    if request.userid == otherid:
        return Response(define.errorpage(request.userid, "You cannot friend yourself."))

    if form.action == "sendfriendrequest":
        if not frienduser.check(request.userid, otherid) and not frienduser.already_pending(request.userid, otherid):
            frienduser.request(request.userid, otherid)
    elif form.action == "withdrawfriendrequest":
        if frienduser.already_pending(request.userid, otherid):
            frienduser.remove_request(request.userid, otherid)
    elif form.action == "unfriend":
        frienduser.remove(request.userid, otherid)

    if form.feature == "pending":
        raise HTTPSeeOther(location="/manage/friends?feature=pending")
    else:  # typical value will be user
        raise HTTPSeeOther(location="/~%s" % (define.get_sysname(define.get_display_name(otherid))))
예제 #20
0
    def POST(self):
        form = web.input(userid="")
        otherid = define.get_int(form.userid)

        if self.user_id == otherid:
            return define.errorpage(self.user_id, "You cannot friend yourself.")

        if form.action == "sendfriendrequest":
            if not frienduser.check(self.user_id, otherid) and not frienduser.already_pending(self.user_id, otherid):
                frienduser.request(self.user_id, otherid)
        elif form.action == "withdrawfriendrequest":
            if frienduser.already_pending(self.user_id, otherid):
                frienduser.remove_request(self.user_id, otherid)
        elif form.action == "unfriend":
            frienduser.remove(self.user_id, otherid)

        if form.feature == "pending":
            raise web.seeother("/manage/friends?feature=pending")
        else:  # typical value will be user
            raise web.seeother("/~%s" % (define.get_sysname(define.get_display_name(otherid))))
예제 #21
0
파일: journal.py 프로젝트: Syfaro/weasyl
def _select_journal_and_check(userid, journalid, rating=None, ignore=True, anyway=False, increment_views=True):
    """Selects a journal, after checking if the user is authorized, etc.

    Args:
        userid (int): Currently authenticating user ID.
        journalid (int): Character ID to fetch.
        rating (int): Maximum rating to display. Defaults to None.
        ignore (bool): Whether to respect ignored or blocked tags. Defaults to True.
        anyway (bool): Whether ignore checks and display anyway. Defaults to False.
        increment_views (bool): Whether to increment the number of views on the submission. Defaults to True.

    Returns:
        A journal and all needed data as a dict.
    """

    query = d.engine.execute("""
        SELECT jo.userid, pr.username, jo.unixtime, jo.title, jo.content, jo.rating, jo.settings, jo.page_views, pr.config
        FROM journal jo JOIN profile pr ON jo.userid = pr.userid
        WHERE jo.journalid = %(id)s
    """, id=journalid).first()

    if journalid and userid in staff.MODS and anyway:
        pass
    elif not query or 'h' in query.settings:
        raise WeasylError('journalRecordMissing')
    elif query.rating > rating and ((userid != query.userid and userid not in staff.MODS) or d.is_sfw_mode()):
        raise WeasylError('RatingExceeded')
    elif 'f' in query.settings and not frienduser.check(userid, query.userid):
        raise WeasylError('FriendsOnly')
    elif ignore and ignoreuser.check(userid, query.userid):
        raise WeasylError('UserIgnored')
    elif ignore and blocktag.check(userid, journalid=journalid):
        raise WeasylError('TagBlocked')

    query = dict(query)

    if increment_views and d.common_view_content(userid, journalid, 'journal'):
        query['page_views'] += 1

    return query
예제 #22
0
파일: submission.py 프로젝트: Syfaro/weasyl
def select_view(userid, submitid, rating, ignore=True, anyway=None):
    query = d.execute("""
        SELECT
            su.userid, pr.username, su.folderid, su.unixtime, su.title, su.content, su.subtype, su.rating, su.settings,
            su.page_views, su.sorttime, pr.config, fd.title
        FROM submission su
            INNER JOIN profile pr USING (userid)
            LEFT JOIN folder fd USING (folderid)
        WHERE su.submitid = %i
    """, [submitid], options=["single", "list"])

    # Sanity check
    if query and userid in staff.MODS and anyway == "true":
        pass
    elif not query or "h" in query[8]:
        raise WeasylError("submissionRecordMissing")
    elif query[7] > rating and ((userid != query[0] and userid not in staff.MODS) or d.is_sfw_mode()):
        raise WeasylError("RatingExceeded")
    elif "f" in query[8] and not frienduser.check(userid, query[0]):
        raise WeasylError("FriendsOnly")
    elif ignore and ignoreuser.check(userid, query[0]):
        raise WeasylError("UserIgnored")
    elif ignore and blocktag.check(userid, submitid=submitid):
        raise WeasylError("TagBlocked")

    # Get submission filename
    submitfile = media.get_submission_media(submitid).get('submission', [None])[0]

    # Get submission text
    if submitfile and submitfile['file_type'] in ['txt', 'htm']:
        submittext = files.read(submitfile['full_file_path'])
    else:
        submittext = None

    embedlink = d.text_first_line(query[5]) if "v" in query[8] else None

    google_doc_embed = None
    if 'D' in query[8]:
        db = d.connect()
        gde = d.meta.tables['google_doc_embeds']
        q = (sa.select([gde.c.embed_url])
             .where(gde.c.submitid == submitid))
        results = db.execute(q).fetchall()
        if not results:
            raise WeasylError("can't find embed information")
        google_doc_embed = results[0]

    tags, artist_tags = searchtag.select_with_artist_tags(submitid)
    settings = d.get_profile_settings(query[0])

    return {
        "submitid": submitid,
        "userid": query[0],
        "username": query[1],
        "folderid": query[2],
        "unixtime": query[3],
        "title": query[4],
        "content": (d.text_first_line(query[5], strip=True) if "v" in query[8] else query[5]),
        "subtype": query[6],
        "rating": query[7],
        "settings": query[8],
        "page_views": (
            query[9] + 1 if d.common_view_content(userid, 0 if anyway == "true" else submitid, "submit") else query[9]),
        "fave_count": d.execute(
            "SELECT COUNT(*) FROM favorite WHERE (targetid, type) = (%i, 's')",
            [submitid], ["element"]),


        "mine": userid == query[0],
        "reported": report.check(submitid=submitid),
        "favorited": favorite.check(userid, submitid=submitid),
        "friends_only": "f" in query[8],
        "hidden_submission": "h" in query[8],
        "collectors": collection.find_owners(submitid),
        "no_request": not settings.allow_collection_requests,

        "text": submittext,
        "sub_media": media.get_submission_media(submitid),
        "user_media": media.get_user_media(query[0]),
        "submit": submitfile,
        "embedlink": embedlink,
        "embed": embed.html(embedlink) if embedlink is not None else None,
        "google_doc_embed": google_doc_embed,


        "tags": tags,
        "artist_tags": artist_tags,
        "removable_tags": searchtag.removable_tags(userid, query[0], tags, artist_tags),
        "can_remove_tags": searchtag.can_remove_tags(userid, query[0]),
        "folder_more": select_near(userid, rating, 1, query[0], query[2], submitid),
        "folder_title": query[12] if query[12] else "Root",


        "comments": comment.select(userid, submitid=submitid),
    }
예제 #23
0
def select_view(userid, submitid, rating, ignore=True, anyway=None):
    query = d.engine.execute("""
        SELECT
            su.userid, pr.username, su.folderid, su.unixtime, su.title, su.content, su.subtype, su.rating, su.settings,
            su.page_views, fd.title, su.favorites, su.image_representations
        FROM submission su
            INNER JOIN profile pr USING (userid)
            LEFT JOIN folder fd USING (folderid)
        WHERE su.submitid = %(id)s
    """,
                             id=submitid).first()

    # Sanity check
    if query and userid in staff.MODS and anyway == "true":
        pass
    elif not query or "h" in query[8]:
        raise WeasylError("submissionRecordMissing")
    elif query[7] > rating and (
        (userid != query[0] and userid not in staff.MODS) or d.is_sfw_mode()):
        raise WeasylError("RatingExceeded")
    elif "f" in query[8] and not frienduser.check(userid, query[0]):
        raise WeasylError("FriendsOnly")
    elif ignore and ignoreuser.check(userid, query[0]):
        raise WeasylError("UserIgnored")
    elif ignore and blocktag.check(userid, submitid=submitid):
        raise WeasylError("TagBlocked")

    # Get submission filename
    submitfile = media.get_submission_media(submitid).get(
        'submission', [None])[0]

    # Get submission text
    if submitfile and submitfile['file_type'] in ['txt', 'htm']:
        submittext = files.read(submitfile['full_file_path'])
    else:
        submittext = None

    embedlink = d.text_first_line(query[5]) if "v" in query[8] else None

    google_doc_embed = None
    if 'D' in query[8]:
        db = d.connect()
        gde = d.meta.tables['google_doc_embeds']
        q = (sa.select([gde.c.embed_url]).where(gde.c.submitid == submitid))
        results = db.execute(q).fetchall()
        if not results:
            raise WeasylError("can't find embed information")
        google_doc_embed = results[0]

    tags, artist_tags = searchtag.select_with_artist_tags(submitid)
    settings = d.get_profile_settings(query[0])

    if query[12] is None:
        sub_media = media.get_submission_media(submitid)
    else:
        sub_media = media.deserialize_image_representations(query[12])

    return {
        "submitid":
        submitid,
        "userid":
        query[0],
        "username":
        query[1],
        "folderid":
        query[2],
        "unixtime":
        query[3],
        "title":
        query[4],
        "content": (d.text_first_line(query[5], strip=True)
                    if "v" in query[8] else query[5]),
        "subtype":
        query[6],
        "rating":
        query[7],
        "settings":
        query[8],
        "page_views": (query[9] + 1 if d.common_view_content(
            userid, 0 if anyway == "true" else submitid, "submit") else
                       query[9]),
        "fave_count":
        query[11],
        "mine":
        userid == query[0],
        "reported":
        report.check(submitid=submitid),
        "favorited":
        favorite.check(userid, submitid=submitid),
        "friends_only":
        "f" in query[8],
        "hidden_submission":
        "h" in query[8],
        "collected":
        collection.owns(userid, submitid),
        "no_request":
        not settings.allow_collection_requests,
        "text":
        submittext,
        "sub_media":
        sub_media,
        "user_media":
        media.get_user_media(query[0]),
        "submit":
        submitfile,
        "embedlink":
        embedlink,
        "embed":
        embed.html(embedlink) if embedlink is not None else None,
        "google_doc_embed":
        google_doc_embed,
        "tags":
        tags,
        "artist_tags":
        artist_tags,
        "removable_tags":
        searchtag.removable_tags(userid, query[0], tags, artist_tags),
        "can_remove_tags":
        searchtag.can_remove_tags(userid, query[0]),
        "folder_more":
        select_near(userid, rating, 1, query[0], query[2], submitid),
        "folder_title":
        query[10] if query[10] else "Root",
        "comments":
        comment.select(userid, submitid=submitid),
    }
예제 #24
0
def send(userid, form):
    form.title = form.title.strip()
    form.content = form.content.strip()

    if not form.content:
        raise WeasylError("contentInvalid")
    elif not form.title:
        raise WeasylError("titleInvalid")
    elif len(form.title) > 100:
        raise WeasylError("titleTooLong")

    users = set(d.get_userid_list(form.recipient))

    # can't send a note to yourself
    users.discard(userid)

    # can't send a note to a user who ignores you
    users.difference_update(
        d.column(
            d.engine.execute(
                "SELECT userid FROM ignoreuser WHERE otherid = %(user)s",
                user=userid)))

    # can't send a note to an unverified user
    users.difference_update(
        d.column(
            d.engine.execute(
                "SELECT userid FROM login WHERE userid = ANY (%(users)s) AND voucher IS NULL",
                users=list(users))))

    # can't send a note to a user you're ignoring
    users.difference_update(ignoreuser.cached_list_ignoring(userid))

    if not users:
        raise WeasylError("recipientInvalid")

    configs = d.engine.execute(
        "SELECT userid, config FROM profile WHERE userid = ANY (%(recipients)s)",
        recipients=list(users)).fetchall()

    if userid not in staff.MODS:
        ignore_global_restrictions = {
            i
            for (i, ) in d.engine.execute(
                "SELECT userid FROM permitted_senders WHERE sender = %(user)s",
                user=userid)
        }

        remove = (
            # Staff notes only
            {j[0]
             for j in configs if "y" in j[1]} |
            # Friend notes only
            {
                j[0]
                for j in configs
                if "z" in j[1] and not frienduser.check(userid, j[0])
            })

        users.difference_update(remove - ignore_global_restrictions)

    if not users:
        raise WeasylError("recipientInvalid")
    elif len(users) > 10:
        raise WeasylError("recipientExcessive")

    d.engine.execute(
        "INSERT INTO message (userid, otherid, title, content, unixtime)"
        " SELECT %(sender)s, recipient, %(title)s, %(content)s, %(now)s"
        " FROM UNNEST (%(recipients)s) AS recipient",
        sender=userid,
        title=form.title,
        content=form.content,
        now=d.get_time(),
        recipients=list(users),
    )

    for u in users:
        d._page_header_info.invalidate(u)

    d.engine.execute(
        """
        INSERT INTO permitted_senders (userid, sender)
            SELECT %(user)s, sender FROM UNNEST (%(recipients)s) AS sender
            ON CONFLICT (userid, sender) DO NOTHING
        """,
        user=userid,
        recipients=list(users),
    )

    if form.mod_copy and userid in staff.MODS:
        mod_content = (
            '## The following message was sent as a note to the user.\n\n### %s\n\n%s'
            % (form.title, form.content))
        if form.staff_note:
            mod_content = '%s\n\n%s' % (form.staff_note, mod_content)
        now = arrow.utcnow()
        mod_copies = []
        for target in users:
            mod_copies.append({
                'userid': userid,
                'target_user': target,
                'unixtime': now,
                'settings': 's',
                'content': mod_content,
            })
        d.engine.execute(d.meta.tables['comments'].insert().values(mod_copies))
예제 #25
0
def insert(userid, submitid=None, charid=None, journalid=None):
    if submitid:
        content_table, id_field, target = "submission", "submitid", submitid
    elif charid:
        content_table, id_field, target = "character", "charid", charid
    else:
        content_table, id_field, target = "journal", "journalid", journalid

    query = d.engine.execute(
        "SELECT userid, settings FROM %s WHERE %s = %i" %
        (content_table, id_field, target), ).first()

    if not query:
        raise WeasylError("TargetRecordMissing")
    elif userid == query[0]:
        raise WeasylError("CannotSelfFavorite")
    elif "f" in query[1] and not frienduser.check(userid, query[0]):
        raise WeasylError("FriendsOnly")
    elif ignoreuser.check(userid, query[0]):
        raise WeasylError("YouIgnored")
    elif ignoreuser.check(query[0], userid):
        raise WeasylError("contentOwnerIgnoredYou")

    notified = []

    def insert_transaction(db):
        insert_result = db.execute(
            'INSERT INTO favorite (userid, targetid, type, unixtime) '
            'VALUES (%(user)s, %(target)s, %(type)s, %(now)s) '
            'ON CONFLICT DO NOTHING',
            user=userid,
            target=d.get_targetid(submitid, charid, journalid),
            type='s' if submitid else 'f' if charid else 'j',
            now=d.get_time())

        if insert_result.rowcount == 0:
            return

        if submitid:
            db.execute(
                "UPDATE submission SET favorites = favorites + 1"
                " WHERE submitid = %(target)s",
                target=submitid,
            )

        if not notified:
            # create a list of users to notify
            notified_ = collection.find_owners(submitid)

            # conditions under which "other" should be notified
            def can_notify(other):
                other_jsonb = d.get_profile_settings(other)
                allow_notify = other_jsonb.allow_collection_notifs
                return allow_notify and not ignoreuser.check(other, userid)

            notified.extend(u for u in notified_ if can_notify(u))
            # always notify for own content
            notified.append(query[0])

        for other in notified:
            welcome.favorite_insert(db,
                                    userid,
                                    submitid=submitid,
                                    charid=charid,
                                    journalid=journalid,
                                    otherid=other)

    d.serializable_retry(insert_transaction)
예제 #26
0
파일: note.py 프로젝트: bubbt/weasyl
def send(userid, form):
    form.title = form.title.strip()
    form.content = form.content.strip()

    if not form.content:
        raise WeasylError("contentInvalid")
    elif not form.title:
        raise WeasylError("titleInvalid")
    elif len(form.title) > 100:
        raise WeasylError("titleTooLong")

    users = set(i for i in d.get_userid_list(form.recipient) if i != userid)
    users.difference_update(
        d.execute("SELECT userid FROM ignoreuser WHERE otherid = %i", [userid],
                  options="within"))
    users.difference_update(
        d.execute("SELECT otherid FROM ignoreuser WHERE userid = %i", [userid],
                  options="within"))
    if not users:
        raise WeasylError("recipientInvalid")

    configs = d.execute(
        "SELECT userid, config FROM profile WHERE userid IN %s",
        [d.sql_number_list(list(users))])

    if userid not in staff.MODS:
        ignore_global_restrictions = {
            i
            for (i, ) in d.engine.execute(
                "SELECT userid FROM permitted_senders WHERE sender = %(user)s",
                user=userid)
        }

        remove = (
            # Staff notes only
            {j[0]
             for j in configs if "y" in j[1]} |
            # Friend notes only
            {
                j[0]
                for j in configs
                if "z" in j[1] and not frienduser.check(userid, j[0])
            })

        users.difference_update(remove - ignore_global_restrictions)

    if not users:
        raise WeasylError("recipientInvalid")
    elif len(users) > 10:
        raise WeasylError("recipientExcessive")

    argv = []
    unixtime = d.get_time()
    statement = [
        "INSERT INTO message (userid, otherid, title, content, unixtime) VALUES"
    ]

    for i in users:
        argv.extend([form.title if form.title else "None", form.content])
        statement.append(" (%i, %i, '%%s', '%%s', %i)," %
                         (userid, i, unixtime))
        d._page_header_info.invalidate(i)

    statement[-1] = statement[-1][:-1]
    d.execute("".join(statement), argv)

    d.engine.execute(
        """
        INSERT INTO permitted_senders (userid, sender)
            SELECT %(user)s, sender FROM UNNEST (%(recipients)s) AS sender
            ON CONFLICT (userid, sender) DO NOTHING
        """,
        user=userid,
        recipients=list(users),
    )

    if form.mod_copy and userid in staff.MODS:
        mod_content = (
            '## The following message was sent as a note to the user.\n\n### %s\n\n%s'
            % (form.title, form.content))
        if form.staff_note:
            mod_content = '%s\n\n%s' % (form.staff_note, mod_content)
        now = arrow.utcnow()
        mod_copies = []
        for target in users:
            mod_copies.append({
                'userid': userid,
                'target_user': target,
                'unixtime': now,
                'settings': 's',
                'content': mod_content,
            })
        d.engine.execute(d.meta.tables['comments'].insert().values(mod_copies))
예제 #27
0
파일: note.py 프로젝트: 0x15/weasyl
def send(userid, form):
    form.title = form.title.strip()
    form.content = form.content.strip()

    if not form.content:
        raise WeasylError("contentInvalid")
    elif not form.title:
        raise WeasylError("titleInvalid")
    elif len(form.title) > 100:
        raise WeasylError("titleTooLong")

    users = set(i for i in d.get_userid_list(form.recipient) if i != userid)
    users.difference_update(
        d.execute("SELECT userid FROM ignoreuser WHERE otherid = %i", [userid], options="within"))
    users.difference_update(
        d.execute("SELECT otherid FROM ignoreuser WHERE userid = %i", [userid], options="within"))
    if not users:
        raise WeasylError("recipientInvalid")

    configs = d.execute(
        "SELECT userid, config FROM profile WHERE userid IN %s",
        [d.sql_number_list(list(users))])

    if userid not in staff.MODS:
        # Staff notes only
        users.difference_update(j[0] for j in configs if "y" in j[1])

        # Friend notes only
        users.difference_update(j[0] for j in configs if "z" in j[1] and not frienduser.check(userid, j[0]))

    if not users:
        raise WeasylError("recipientInvalid")
    elif len(users) > 10:
        raise WeasylError("recipientExcessive")

    argv = []
    unixtime = d.get_time()
    statement = ["INSERT INTO message (userid, otherid, title, content, unixtime) VALUES"]

    for i in users:
        argv.extend([form.title if form.title else "None", form.content])
        statement.append(" (%i, %i, '%%s', '%%s', %i)," % (userid, i, unixtime))
        d._page_header_info.invalidate(i)

    statement[-1] = statement[-1][:-1]
    d.execute("".join(statement), argv)

    if form.mod_copy and userid in staff.MODS:
        mod_content = (
            '## The following message was sent as a note to the user.\n\n### %s\n\n%s' % (
                form.title, form.content))
        if form.staff_note:
            mod_content = '%s\n\n%s' % (form.staff_note, mod_content)
        now = arrow.utcnow()
        mod_copies = []
        for target in users:
            mod_copies.append({
                'userid': userid,
                'target_user': target,
                'unixtime': now,
                'settings': 's',
                'content': mod_content,
            })
        d.engine.execute(
            d.meta.tables['comments'].insert()
            .values(mod_copies))