def edit_email_password(userid, username, password, newemail, newemailcheck, newpassword, newpasscheck): import login # Check that credentials are correct logid, logerror = login.authenticate_bcrypt(username, password, session=False) if userid != logid or logerror is not None: raise WeasylError("loginInvalid") if newemail: if newemail != newemailcheck: raise WeasylError("emailMismatch") elif login.email_exists(newemail): raise WeasylError("emailExists") if newpassword: if newpassword != newpasscheck: raise WeasylError("passwordMismatch") elif not login.password_secure(newpassword): raise WeasylError("passwordInsecure") if newemail: d.execute("UPDATE login SET email = '%s' WHERE userid = %i", [newemail, userid]) if newpassword: d.execute("UPDATE authbcrypt SET hashsum = '%s' WHERE userid = %i", [login.passhash(newpassword), userid])
def twitter_card(submitid): query = d.execute( """ SELECT su.title, su.settings, su.content, su.subtype, su.userid, pr.username, pr.full_name, pr.config, ul.link_value, su.rating FROM submission su INNER JOIN profile pr USING (userid) LEFT JOIN user_links ul ON su.userid = ul.userid AND ul.link_type = 'twitter' WHERE submitid = %i LIMIT 1 """, [submitid], ["single"]) if not query: raise WeasylError("submissionRecordMissing") title, settings, content, subtype, userid, username, full_name, config, twitter, rating = query if 'h' in settings: raise WeasylError("submissionRecordMissing") elif 'f' in settings: raise WeasylError("FriendsOnly") if 'v' in settings: content = d.text_first_line(content, strip=True) content = d.summarize(html.strip_html(content)) if not content: content = "[This submission has no description.]" ret = { 'url': d.absolutify_url('/submission/%s/%s' % (submitid, text.slug_for(title))), } if twitter: ret['creator'] = '@%s' % (twitter.lstrip('@'), ) ret['title'] = title else: ret['title'] = '%s by %s' % (title, full_name) if ratings.CODE_MAP[rating].minimum_age >= 18: ret['card'] = 'summary' ret['description'] = 'This image is rated 18+ and only viewable on weasyl.com' return ret ret['description'] = content subcat = subtype / 1000 * 1000 media_items = media.get_submission_media(submitid) if subcat == m.ART_SUBMISSION_CATEGORY and media_items.get('submission'): ret['card'] = 'photo' ret['image:src'] = d.absolutify_url( media_items['submission'][0]['display_url']) else: ret['card'] = 'summary' thumb = media_items.get('thumbnail-custom') or media_items.get( 'thumbnail-generated') if thumb: ret['image:src'] = d.absolutify_url(thumb[0]['display_url']) return ret
def check_google_doc_embed_data(embedlink): m = text.url_regexp.search(embedlink) if not m: raise WeasylError('googleDocsEmbedLinkInvalid') embedlink = m.group() parsed = urlparse.urlparse(embedlink) if parsed.scheme != 'https' or parsed.netloc != 'docs.google.com': raise WeasylError('googleDocsEmbedLinkInvalid')
def wrapper(*a, **kw): try: return func(*a, **kw) except Exception as e: web.ctx.log_exc(level=logging.DEBUG) w = WeasylError('httpError') w.error_suffix = 'The original error was: %s' % (e,) raise w
def edit_preferences(userid, timezone=None, preferences=None, jsonb_settings=None): """ Apply changes to stored preferences for a given user. :param userid: The userid to apply changes to :param timezone: (optional) new Timezone to set for user :param preferences: (optional) old-style char preferences, overwrites all previous settings :param jsonb_settings: (optional) JSON preferences, overwrites all previous settings :return: None """ config = d.get_config(userid) tooyoung = False if preferences is not None: tooyoung |= get_user_age(userid) < preferences.rating.minimum_age if jsonb_settings is not None: sfwrating = jsonb_settings.max_sfw_rating sfwrating = ratings.CODE_MAP.get(sfwrating, ratings.GENERAL) tooyoung |= get_user_age(userid) < sfwrating.minimum_age if tooyoung: raise WeasylError("birthdayInsufficient") if timezone is not None and timezone not in pytz.all_timezones: raise WeasylError('invalidTimezone') db = d.connect() updates = {} if preferences is not None: # update legacy preferences # clear out the option codes that are being replaced. for i in Config.all_option_codes: config = config.replace(i, "") config_str = config + preferences.to_code() updates['config'] = config_str d._get_config.invalidate(userid) if jsonb_settings is not None: # update jsonb preferences updates['jsonb_settings'] = jsonb_settings.get_raw() d._get_profile_settings.invalidate(userid) d.engine.execute( tables.profile.update().where(tables.profile.c.userid == userid), updates) # update TZ if timezone is not None: tz = db.query(orm.UserTimezone).get(userid) if tz is None: tz = orm.UserTimezone(userid=userid) db.add(tz) tz.timezone = timezone db.flush() tz.cache() else: db.flush()
def edit_streaming_settings(my_userid, userid, profile, set_stream=None, stream_length=0): if set_stream == 'start': try: stream_length = int(stream_length) except: raise WeasylError("streamDurationOutOfRange") if stream_length < 1 or stream_length > 360: raise WeasylError("streamDurationOutOfRange") if set_stream == 'start' and not profile.stream_url: raise WeasylError("streamLocationNotSet") # unless we're specifically still streaming, clear the user_streams record if set_stream != 'still': d.execute("DELETE FROM user_streams WHERE userid = %i", [userid]) settings_flag = '' stream_status = None # if we're starting to stream, update user_streams to reflect that if set_stream == 'start': now = d.get_time() stream_end = now + stream_length * 60 # stream_length is minutes; we need seconds d.execute("INSERT INTO user_streams VALUES (%i, %i, %i)", [userid, now, stream_end]) stream_status = 'n' # if we're going to stream later, update profile.settings to reflect that elif set_stream == 'later': settings_flag = stream_status = 'l' # if stream_status is None, any rows in `welcome` will get cleared. but, if # the user is still streaming, that shouldn't happen. otherwise, `welcome` # will get updated with the current stream state. if set_stream != 'still': welcome.stream_insert(userid, stream_status) d.execute( "UPDATE profile " "SET (stream_text, stream_url, settings) = ('%s', '%s', REGEXP_REPLACE(settings, '[nli]', '') || '%s') " "WHERE userid = %i", [profile.stream_text, profile.stream_url, settings_flag, userid]) if my_userid != userid: from weasyl import moderation note_body = ('- Stream url: %s\n' '- Stream description: %s\n' '- Stream status: %s' % (profile.stream_url, profile.stream_text, STREAMING_ACTION_MAP[set_stream])) moderation.note_about(my_userid, userid, 'Streaming settings updated:', note_body)
def set(userid, username): if login.username_exists(username): raise WeasylError("usernameExists") elif not d.get_premium(None, userid): raise WeasylError("InsufficientPermissions") d.execute("DELETE FROM useralias WHERE userid = %i AND settings ~ 'p'", [userid]) d.execute("INSERT INTO useralias VALUES (%i, '%s', 'p')", [userid, username])
def force_resetbirthday(userid, birthday): if not birthday: raise WeasylError("birthdayInvalid") elif birthday > d.get_time(): raise WeasylError("birthdayInvalid") d.execute("UPDATE userinfo SET birthday = %i WHERE userid = %i", [birthday, userid]) d.execute( "UPDATE login SET settings = REPLACE(settings, 'i', '') WHERE userid = %i", [userid]) d.get_login_settings.invalidate(userid)
def offer(userid, submitid, otherid): query = d.execute("SELECT userid, rating, settings FROM submission WHERE submitid = %i", [submitid], options="single") if not query or "h" in query[2]: raise WeasylError("Unexpected") elif userid != query[0]: raise WeasylError("Unexpected") # Check collection acceptability if otherid: rating = d.get_rating(otherid) if rating < query[1]: raise WeasylError("collectionUnacceptable") if "f" in query[2]: raise WeasylError("collectionUnacceptable") if ignoreuser.check(otherid, userid): raise WeasylError("IgnoredYou") if ignoreuser.check(userid, otherid): raise WeasylError("YouIgnored") if blocktag.check(otherid, submitid=submitid): raise WeasylError("collectionUnacceptable") try: d.execute("INSERT INTO collection (userid, submitid, unixtime) VALUES (%i, %i, %i)", [otherid, submitid, d.get_time()]) except PostgresError: raise WeasylError("collectionExists") welcome.collectoffer_insert(userid, otherid, submitid)
def insert(userid, otherid): if ignoreuser.check(otherid, userid): raise WeasylError("IgnoredYou") elif ignoreuser.check(userid, otherid): raise WeasylError("YouIgnored") try: d.execute("INSERT INTO watchuser VALUES (%i, %i, '%s')", [ userid, otherid, WatchSettings.from_code(d.get_config(userid)).to_code() ]) except IntegrityError: pass welcome.followuser_remove(userid, otherid) welcome.followuser_insert(userid, otherid)
def gallery_blacklisted_tags(userid, otherid): if userid not in staff.MODS: raise WeasylError("Unexpected") query = d.engine.execute(""" SELECT title FROM ( SELECT tagid FROM submission INNER JOIN searchmapsubmit ON submitid = targetid INNER JOIN blocktag USING (tagid) WHERE submission.userid = %(other)s AND blocktag.userid = %(user)s AND submission.rating >= blocktag.rating UNION SELECT tagid FROM character INNER JOIN searchmapchar ON charid = targetid INNER JOIN blocktag USING (tagid) WHERE character.userid = %(other)s AND blocktag.userid = %(user)s AND character.rating >= blocktag.rating ) AS t INNER JOIN searchtag USING (tagid) ORDER BY title """, user=userid, other=otherid) return [row.title for row in query]
def submissionsbyuser(userid, form): if userid not in staff.MODS: raise WeasylError("Unexpected") query = d.execute( """ SELECT su.submitid, su.title, su.rating, su.unixtime, su.userid, pr.username, su.settings FROM submission su INNER JOIN profile pr USING (userid) WHERE su.userid = (SELECT userid FROM login WHERE login_name = '%s') ORDER BY su.submitid DESC """, [d.get_sysname(form.name)]) ret = [{ "contype": 10, "submitid": i[0], "title": i[1], "rating": i[2], "unixtime": i[3], "userid": i[4], "username": i[5], "settings": i[6], } for i in query] media.populate_with_submission_media(ret) return ret
def select_manage(userid): query = d.execute( """ SELECT lo.userid, lo.last_login, lo.email, pr.unixtime, pr.username, pr.full_name, pr.catchphrase, ui.birthday, ui.gender, ui.country, pr.config FROM login lo INNER JOIN profile pr USING (userid) INNER JOIN userinfo ui USING (userid) WHERE lo.userid = %i """, [userid], ["single"]) if not query: raise WeasylError("Unexpected") return { "userid": query[0], "last_login": query[1], "email": query[2], "unixtime": query[3], "username": query[4], "full_name": query[5], "catchphrase": query[6], "birthday": query[7], "gender": query[8], "country": query[9], "config": query[10], "staff_notes": shout.count(userid, staffnotes=True), }
def shrinkcrop(im, size, bounds=None): ret = correct_image_and_call(_shrinkcrop, im, size, bounds) if ret.size != size or (len(ret) == 1 and ret[0].size != size): ignored_sizes = ret.size, ret[0].size # to log these locals raise WeasylError('thumbnailingMessedUp') ignored_sizes # to shut pyflakes up return ret
def check_for_duplicate_media(userid, mediaid): db = d.connect() q = (db.query(orm.Submission).filter_by( userid=userid, is_hidden=False).join( orm.SubmissionMediaLink).filter_by(mediaid=mediaid, link_type='submission')) if q.first(): raise WeasylError('duplicateSubmission')
def accept(userid, otherid): if check(userid, otherid): raise WeasylError("Unexpected") d.execute( "UPDATE frienduser SET settings = REPLACE(settings, 'p', '')" " WHERE (userid, otherid) = (%i, %i)", [otherid, userid]) welcome.frienduseraccept_insert(userid, otherid) welcome.frienduserrequest_remove(userid, otherid)
def select_settings(userid, otherid): query = d.execute( "SELECT settings FROM watchuser WHERE (userid, otherid) = (%i, %i)", [userid, otherid], ["single"]) if not query: raise WeasylError("watchuserRecordMissing") return query[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).fetchone() 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
def removecoverart(userid, submitid): sub = Submission.query.get(submitid) if not sub.cover_media: raise WeasylError("noCover") submission.reupload_cover(userid, submitid, None) otherid = sub.owner.userid title = sub.title note_about( userid, otherid, 'Cover was removed for ' + text.markdown_link(title, '/submission/%s?anyway=true' % submitid))
def reupload_cover(userid, submitid, coverfile): query = d.execute( "SELECT userid, subtype, rating FROM submission WHERE submitid = %i", [submitid], ["single", "list"]) if not query: raise WeasylError("Unexpected") elif userid not in staff.MODS and userid != query[0]: raise WeasylError("Unexpected") elif query[1] < 2000: raise WeasylError("Unexpected") cover_media_item = media.make_cover_media_item(coverfile) if not cover_media_item: orm.SubmissionMediaLink.clear_link(submitid, 'cover') else: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'cover', cover_media_item, rating=query[2])
def create_generic(userid, submission, **kwargs): tags = kwargs['tags'] if submission.subtype not in valid_types: submission.subtype = expected_type * 1000 + 999 if not submission.title: raise WeasylError("titleInvalid") elif not submission.rating: raise WeasylError("ratingInvalid") elif len(tags) < 2: raise WeasylError("notEnoughTags") elif not folder.check(userid, submission.folderid): raise WeasylError("Unexpected") profile.check_user_rating_allowed(userid, submission.rating) return create_specific(userid=userid, submission=submission, **kwargs)
def manageuser(userid, form): if userid not in staff.MODS: raise WeasylError("Unexpected") query = d.execute( "SELECT userid, username, config, profile_text, catchphrase FROM profile" " WHERE userid = (SELECT userid FROM login WHERE login_name = '%s')", [d.get_sysname(form.name)], ["single"]) if not query: raise WeasylError("noUser") return { "userid": query[0], "username": query[1], "config": query[2], "profile_text": query[3], "catchphrase": query[4], "user_media": media.get_user_media(query[0]), "staff_notes": shout.count(query[0], staffnotes=True), }
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.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).fetchone() 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
def reupload(userid, charid, submitdata): submitsize = len(submitdata) if not submitsize: raise WeasylError("submitSizeZero") elif submitsize > 10 * _MEGABYTE: raise WeasylError("submitSizeExceedsLimit") # Select character data query, = define.engine.execute(""" SELECT userid, settings FROM character WHERE charid = %(character)s AND settings !~ 'h' """, character=charid) if userid != query.userid: raise WeasylError("Unexpected") im = image.from_string(submitdata) submitextension = image.image_extension(im) # Check invalid file data if not submitextension: raise WeasylError("submitType") # Make submission file submitfile = files.make_resource(userid, charid, "char/submit", submitextension) files.ensure_file_directory(submitfile) im.write(submitfile) # Make cover file image.make_cover( submitfile, files.make_resource(userid, charid, "char/cover", submitextension)) # Update settings settings = re.sub(r'[~=].', '', query.settings) settings += files.typeflag("submit", submitextension) settings += files.typeflag("cover", submitextension) define.engine.execute(""" UPDATE character SET settings = %(settings)s WHERE charid = %(character)s """, settings=settings, character=charid)
def create(userid, journal, friends_only=False, tags=None): # Check invalid arguments if not journal.title: raise WeasylError("titleInvalid") elif not journal.content: raise WeasylError("contentInvalid") elif not journal.rating: raise WeasylError("ratingInvalid") profile.check_user_rating_allowed(userid, journal.rating) # Assign settings settings = "f" if friends_only else "" # Create journal jo = d.meta.tables["journal"] journalid = d.engine.execute(jo.insert().returning(jo.c.journalid), { "userid": userid, "title": journal.title, "rating": journal.rating.code, "unixtime": arrow.now(), "settings": settings, }).scalar() # Write journal file files.make_path(journalid, "journal") files.write(files.make_resource(userid, journalid, "journal/submit"), journal.content) # Assign search tags searchtag.associate(userid, tags, journalid=journalid) # Create notifications if "m" not in settings: welcome.journal_insert(userid, journalid, rating=journal.rating.code, settings=settings) d.metric('increment', 'journals') return journalid
def remove(userid, journalid): ownerid = d.get_ownerid(journalid=journalid) if userid not in staff.MODS and userid != ownerid: raise WeasylError("InsufficientPermissions") query = d.execute("UPDATE journal SET settings = settings || 'h'" " WHERE journalid = %i AND settings !~ 'h' RETURNING journalid", [journalid]) if query: welcome.journal_remove(journalid) return ownerid
def request(userid, submitid, otherid): query = d.engine.execute( "SELECT userid, rating, settings " "FROM submission WHERE submitid = %(submission)s", submission=submitid).first() rating = d.get_rating(userid) if not query or "h" in query.settings: raise WeasylError("Unexpected") if otherid != query.userid: raise WeasylError("Unexpected") # not checking for blocktags here because if you want to collect # something with a tag you don't like that's your business if rating < query.rating: raise WeasylError("RatingExceeded") if "f" in query.settings: raise WeasylError("collectionUnacceptable") if ignoreuser.check(otherid, userid): raise WeasylError("IgnoredYou") if ignoreuser.check(userid, otherid): raise WeasylError("YouIgnored") if _check_throttle(userid, otherid): raise WeasylError("collectionThrottle") settings = d.get_profile_settings(otherid) if not settings.allow_collection_requests: raise WeasylError("Unexpected") request_settings = "r" try: d.engine.execute( "INSERT INTO collection (userid, submitid, unixtime, settings) " "VALUES (%(userid)s, %(submitid)s, %(now)s, %(settings)s)", userid=userid, submitid=submitid, now=d.get_time(), settings=request_settings) except PostgresError: raise WeasylError("collectionExists") welcome.collectrequest_insert(userid, otherid, submitid)
def remove(userid, charid): ownerid = define.get_ownerid(charid=charid) if userid not in staff.MODS and userid != ownerid: raise WeasylError("InsufficientPermissions") query = define.execute("UPDATE character SET settings = settings || 'h'" " WHERE charid = %i AND settings !~ 'h'" " RETURNING charid", [charid]) if query: welcome.character_remove(charid) return ownerid
def edit(userid, character, friends_only): query = define.execute("SELECT userid, settings FROM character WHERE charid = %i", [character.charid], options="single") if not query or "h" in query[1]: raise WeasylError("Unexpected") elif userid != query[0] and userid not in staff.MODS: raise WeasylError("InsufficientPermissions") elif not character.char_name: raise WeasylError("characterNameInvalid") elif not character.rating: raise WeasylError("Unexpected") profile.check_user_rating_allowed(userid, character.rating) # Assign settings settings = [query[1].replace("f", "")] settings.append("f" if friends_only else "") settings = "".join(settings) if "f" in settings: welcome.character_remove(character.charid) define.execute( """ UPDATE character SET (char_name, age, gender, height, weight, species, content, rating, settings) = ('%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, '%s') WHERE charid = %i """, [character.char_name, character.age, character.gender, character.height, character.weight, character.species, character.content, character.rating.code, settings, character.charid]) if userid != query[0]: from weasyl import moderation moderation.note_about( userid, query[0], 'The following character was edited:', '- ' + text.markdown_link(character.char_name, '/character/%s?anyway=true' % (character.charid,)))
def remove(userid, submitid): ownerid = d.get_ownerid(submitid=submitid) if userid not in staff.MODS and userid != ownerid: raise WeasylError("InsufficientPermissions") query = d.execute( "UPDATE submission SET settings = settings || 'h'" " WHERE submitid = %i AND settings !~ 'h' RETURNING submitid", [submitid]) if query: welcome.submission_remove(submitid) return ownerid