def finduser(userid, form): form.userid = d.get_int(form.userid) lo = d.meta.tables['login'] sh = d.meta.tables['comments'] q = d.sa.select([ lo.c.userid, lo.c.login_name, lo.c.email, (d.sa.select([d.sa.func.count()]) .select_from(sh) .where(sh.c.target_user == lo.c.userid) .where(sh.c.settings.op('~')('s'))).label('staff_notes'), ]) if form.userid: q = q.where(lo.c.userid == form.userid) elif form.username: q = q.where(lo.c.login_name.op('~')(form.username)) elif form.email: q = q.where(d.sa.or_( lo.c.email.op('~')(form.email), lo.c.email.op('ilike')('%%%s%%' % form.email), )) else: return [] q = q.limit(100).order_by(lo.c.login_name.asc()) db = d.connect() return db.execute(q)
def is_hidden(submitid): db = d.connect() su = d.meta.tables['submission'] q = d.sa.select([su.c.settings.op('~')('h') ]).where(su.c.submitid == submitid) results = db.execute(q).fetchall() return bool(results and results[0][0])
def finduser(userid, form): form.userid = d.get_int(form.userid) lo = d.meta.tables['login'] sh = d.meta.tables['comments'] q = d.sa.select([ lo.c.userid, lo.c.login_name, lo.c.email, (d.sa.select([ d.sa.func.count() ]).select_from(sh).where(sh.c.target_user == lo.c.userid).where( sh.c.settings.op('~')('s'))).label('staff_notes'), ]) if form.userid: q = q.where(lo.c.userid == form.userid) elif form.username: q = q.where(lo.c.login_name.op('~')(form.username)) elif form.email: q = q.where( d.sa.or_( lo.c.email.op('~')(form.email), lo.c.email.op('ilike')('%%%s%%' % form.email), )) else: return [] q = q.limit(100).order_by(lo.c.login_name.asc()) db = d.connect() return db.execute(q)
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 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 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 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 select_friends(userid, otherid, limit=None, backid=None, nextid=None, choose=False): """ Return accepted friends. If `choose` is an integer, results will be ordered randomly. """ fr = d.meta.tables['frienduser'] pr = d.meta.tables['profile'] iu = d.meta.tables['ignoreuser'] friends = d.sa.union( (d.sa.select([fr.c.otherid, pr.c.username, pr.c.config]).select_from( fr.join(pr, fr.c.otherid == pr.c.userid)).where( d.sa.and_(fr.c.userid == otherid, fr.c.settings.op('!~')('p')))), (d.sa.select([fr.c.userid, pr.c.username, pr.c.config]).select_from( fr.join(pr, fr.c.userid == pr.c.userid)).where( d.sa.and_(fr.c.otherid == otherid, fr.c.settings.op('!~')('p'))))) friends = friends.alias('friends') query = d.sa.select(friends.c) if userid: query = query.where(~friends.c.otherid.in_( d.sa.select([iu.c.otherid]).where(iu.c.userid == userid))) if backid: query = query.where( friends.c.username < d.sa.select([pr.c.username]).where( pr.c.userid == backid)) elif nextid: query = query.where( friends.c.username > d.sa.select([pr.c.username]).where( pr.c.userid == nextid)) if choose: query = query.order_by('RANDOM()') else: query = query.order_by( friends.c.username.desc() if backid else friends.c.username.asc()) query = query.limit(limit) db = d.connect() query = [{ "userid": r.otherid, "username": r.username, } for r in db.execute(query)] ret = (d.get_random_set(query, choose) if choose else query[::-1] if backid else query) media.populate_with_user_media(ret) return ret
def editprofiletext(userid, otherid, content): pr = d.meta.tables['profile'] db = d.connect() condition = pr.c.userid == otherid previous_profile = db.scalar(sa.select([pr.c.profile_text]).where(condition)) db.execute(pr.update().where(condition).values(profile_text=content)) note_about( userid, otherid, 'Profile text replaced with:', '%s\n\n## Profile text was:\n\n%s' % (content, previous_profile))
def editprofiletext(userid, otherid, content): pr = d.meta.tables['profile'] db = d.connect() condition = pr.c.userid == otherid previous_profile = db.scalar( sa.select([pr.c.profile_text]).where(condition)) db.execute(pr.update().where(condition).values(profile_text=content)) note_about( userid, otherid, 'Profile text replaced with:', '%s\n\n## Profile text was:\n\n%s' % (content, previous_profile))
def editcatchphrase(userid, otherid, content): pr = d.meta.tables['profile'] db = d.connect() condition = pr.c.userid == otherid previous_catchphrase = db.scalar( sa.select([pr.c.catchphrase]).where(condition)) db.execute(pr.update().where(condition).values(catchphrase=content)) note_about( userid, otherid, 'Catchphrase replaced with:', '%s\n\n## Catchphrase was:\n\n%s' % (content, previous_catchphrase))
def editcatchphrase(userid, otherid, content): pr = d.meta.tables['profile'] db = d.connect() condition = pr.c.userid == otherid previous_catchphrase = db.scalar(sa.select([pr.c.catchphrase]).where(condition)) db.execute(pr.update().where(condition).values(catchphrase=content)) note_about( userid, otherid, 'Catchphrase replaced with:', '%s\n\n## Catchphrase was:\n\n%s' % (content, previous_catchphrase))
def note_about(userid, target_user, title, message=None): staff_note = '## ' + title if message: staff_note = '%s\n\n%s' % (staff_note, message) db = d.connect() db.execute( d.meta.tables['comments'].insert() .values( userid=userid, target_user=target_user, unixtime=arrow.utcnow(), settings='s', content=staff_note, ))
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, }
def note_about(userid, target_user, title, message=None): staff_note = '## ' + title if message: staff_note = '%s\n\n%s' % (staff_note, message) db = d.connect() db.execute(d.meta.tables['comments'].insert().values( userid=userid, target_user=target_user, unixtime=arrow.utcnow(), settings='s', content=staff_note, ))
def select_friends(userid, otherid, limit=None, backid=None, nextid=None, choose=False): """ Return accepted friends. If `choose` is an integer, results will be ordered randomly. """ fr = d.meta.tables['frienduser'] pr = d.meta.tables['profile'] iu = d.meta.tables['ignoreuser'] friends = d.sa.union( (d.sa .select([fr.c.otherid, pr.c.username, pr.c.config]) .select_from(fr.join(pr, fr.c.otherid == pr.c.userid)) .where(d.sa.and_(fr.c.userid == otherid, fr.c.settings.op('!~')('p')))), (d.sa .select([fr.c.userid, pr.c.username, pr.c.config]) .select_from(fr.join(pr, fr.c.userid == pr.c.userid)) .where(d.sa.and_(fr.c.otherid == otherid, fr.c.settings.op('!~')('p'))))) friends = friends.alias('friends') query = d.sa.select(friends.c) if userid: query = query.where( ~friends.c.otherid.in_(d.sa.select([iu.c.otherid]).where(iu.c.userid == userid))) if backid: query = query.where( friends.c.username < d.sa.select([pr.c.username]).where(pr.c.userid == backid)) elif nextid: query = query.where( friends.c.username > d.sa.select([pr.c.username]).where(pr.c.userid == nextid)) if choose: query = query.order_by('RANDOM()') else: query = query.order_by( friends.c.username.desc() if backid else friends.c.username.asc()) query = query.limit(limit) db = d.connect() query = [{ "userid": r.otherid, "username": r.username, } for r in db.execute(query)] ret = (d.get_random_set(query, choose) if choose else query[::-1] if backid else query) media.populate_with_user_media(ret) return ret
def _post_to_twitter_about(submitid, title, rating, tags): url = d.absolutify_url('/submission/%s/%s' % (submitid, text.slug_for(title))) st = d.meta.tables['searchtag'] sms = d.meta.tables['searchmapsubmit'] q = (sa.select([st.c.title]) .select_from(st.join(sms, st.c.tagid == sms.c.tagid)) .where(st.c.title.in_(t.lower() for t in tags)) .group_by(st.c.title) .order_by(sa.func.count().desc())) account = 'WeasylCritique' if rating in (ratings.MATURE.code, ratings.EXPLICIT.code): account = 'WZLCritiqueNSFW' length = 26 selected_tags = [] db = d.connect() for tag, in db.execute(q): if len(tag) + 2 + length > 140: break selected_tags.append('#' + tag) length += len(tag) + 2 twits.post(account, u'%s %s' % (url, ' '.join(selected_tags)))
def _post_to_twitter_about(submitid, title, rating, tags): url = d.absolutify_url('/submission/%s/%s' % (submitid, text.slug_for(title))) st = d.meta.tables['searchtag'] sms = d.meta.tables['searchmapsubmit'] q = (sa.select([st.c.title]).select_from( st.join(sms, st.c.tagid == sms.c.tagid)).where( st.c.title.in_(t.lower() for t in tags)).group_by( st.c.title).order_by(sa.func.count().desc())) account = 'WeasylCritique' if rating in (ratings.MATURE.code, ratings.EXPLICIT.code): account = 'WZLCritiqueNSFW' length = 26 selected_tags = [] db = d.connect() for tag, in db.execute(q): if len(tag) + 2 + length > 140: break selected_tags.append('#' + tag) length += len(tag) + 2 twits.post(account, u'%s %s' % (url, ' '.join(selected_tags)))
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), }
def create_literary(userid, submission, embedlink=None, friends_only=False, tags=None, coverfile=None, thumbfile=None, submitfile=None, critique=False, create_notifications=True): premium = d.get_premium(userid) if embedlink: check_google_doc_embed_data(embedlink) # Determine filesizes coversize = len(coverfile) thumbsize = len(thumbfile) submitsize = len(submitfile) if not submitsize and not embedlink: raise WeasylError("submitSizeZero") elif coversize > 10 * _MEGABYTE: raise WeasylError("coverSizeExceedsLimit") elif thumbsize > 10 * _MEGABYTE: raise WeasylError("thumbSizeExceedsLimit") if submitsize: submitextension = files.get_extension_for_category(submitfile, m.TEXT_SUBMISSION_CATEGORY) if submitextension is None: raise WeasylError("submitType") if _limit(submitsize, submitextension, premium): raise WeasylError("submitSizeExceedsLimit") submit_media_item = orm.fetch_or_create_media_item( submitfile, file_type=submitextension.lstrip('.')) check_for_duplicate_media(userid, submit_media_item.mediaid) else: submit_media_item = None thumb_media_item = media.make_cover_media_item(thumbfile) cover_media_item = media.make_cover_media_item(coverfile) if cover_media_item and not thumb_media_item: thumb_media_item = cover_media_item # Assign settings settings = [] settings.append("f" if friends_only else "") settings.append("q" if critique else "") if embedlink: settings.append('D') settings = "".join(settings) # Create submission # TODO(kailys): use ORM object db = d.connect() now = arrow.get() try: q = ( d.meta.tables['submission'].insert().values([{ "folderid": submission.folderid, "userid": userid, "unixtime": now, "title": submission.title, "content": submission.content, "subtype": submission.subtype, "rating": submission.rating.code, "settings": settings, "sorttime": now, }]) .returning(d.meta.tables['submission'].c.submitid)) submitid = db.scalar(q) if embedlink: q = (d.meta.tables['google_doc_embeds'].insert() .values(submitid=submitid, embed_url=embedlink)) db.execute(q) except: files.clear_temporary(userid) raise # Assign search tags searchtag.associate(userid, tags, submitid=submitid) if submit_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'submission', submit_media_item, rating=submission.rating.code) if cover_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'cover', cover_media_item, rating=submission.rating.code) if thumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-source', thumb_media_item) # Create notifications if create_notifications: _create_notifications(userid, submitid, submission.rating, settings, submission.title, tags) # Clear temporary files files.clear_temporary(userid) d.metric('increment', 'submissions') d.metric('increment', 'literarysubmissions') return submitid, bool(thumb_media_item)
def create_multimedia(userid, submission, embedlink=None, friends_only=None, tags=None, coverfile=None, thumbfile=None, submitfile=None, critique=False, create_notifications=True, auto_thumb=False): premium = d.get_premium(userid) embedlink = embedlink.strip() # Determine filesizes coversize = len(coverfile) thumbsize = len(thumbfile) submitsize = len(submitfile) if not submitsize and not embedlink: raise WeasylError("submitSizeZero") elif embedlink and not embed.check_valid(embedlink): raise WeasylError("embedlinkInvalid") elif coversize > 10 * _MEGABYTE: raise WeasylError("coverSizeExceedsLimit") elif thumbsize > 10 * _MEGABYTE: raise WeasylError("thumbSizeExceedsLimit") if submitsize: submitextension = files.get_extension_for_category( submitfile, m.MULTIMEDIA_SUBMISSION_CATEGORY) if submitextension is None: raise WeasylError("submitType") elif submitextension not in [".mp3", ".swf"] and not embedlink: raise WeasylError("submitType") elif _limit(submitsize, submitextension, premium): raise WeasylError("submitSizeExceedsLimit") submit_media_item = orm.fetch_or_create_media_item( submitfile, file_type=submitextension.lstrip('.')) check_for_duplicate_media(userid, submit_media_item.mediaid) else: submit_media_item = None thumb_media_item = media.make_cover_media_item(thumbfile) cover_media_item = media.make_cover_media_item(coverfile) if cover_media_item and not thumb_media_item: thumb_media_item = cover_media_item tempthumb_media_item = None im = None if auto_thumb: if thumbsize == 0 and coversize == 0: # Fetch default thumbnail from source if available thumb_url = embed.thumbnail(embedlink) if thumb_url: resp = d.http_get(thumb_url, timeout=5) im = image.from_string(resp.content) if not im and (thumbsize or coversize): im = image.from_string(thumbfile or coverfile) if im: tempthumb = images.make_thumbnail(im) tempthumb_type = images.image_file_type(tempthumb) tempthumb_media_item = orm.fetch_or_create_media_item( tempthumb.to_buffer(format=tempthumb_type), file_type=tempthumb_type, im=tempthumb) # Assign settings settings = [] settings.append("f" if friends_only else "") settings.append("q" if critique else "") settings.append("v" if embedlink else "") settings = "".join(settings) # Inject embedlink if embedlink: submission.content = "".join([embedlink, "\n", submission.content]) # Create submission db = d.connect() now = arrow.get() try: q = (d.meta.tables['submission'].insert().values([{ "folderid": submission.folderid, "userid": userid, "unixtime": now, "title": submission.title, "content": submission.content, "subtype": submission.subtype, "rating": submission.rating, "settings": settings, "sorttime": now, }]).returning(d.meta.tables['submission'].c.submitid)) submitid = db.scalar(q) except PostgresError: files.clear_temporary(userid) raise # Assign search tags searchtag.associate(userid, tags, submitid=submitid) if submit_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'submission', submit_media_item, rating=submission.rating.code) if cover_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'cover', cover_media_item, rating=submission.rating.code) if thumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-source', thumb_media_item) if tempthumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-custom', tempthumb_media_item) # Create notifications if create_notifications: _create_notifications(userid, submitid, submission.rating, settings, submission.title, tags) # Clear temporary files files.clear_temporary(userid) d.metric('increment', 'submissions') d.metric('increment', 'multimediasubmissions') return submitid, bool(thumb_media_item)
def create_literary(userid, submission, embedlink=None, friends_only=False, tags=None, coverfile=None, thumbfile=None, submitfile=None, critique=False, create_notifications=True): premium = d.get_premium(userid) if embedlink: check_google_doc_embed_data(embedlink) # Determine filesizes coversize = len(coverfile) thumbsize = len(thumbfile) submitsize = len(submitfile) if not submitsize and not embedlink: raise WeasylError("submitSizeZero") elif coversize > 10 * _MEGABYTE: raise WeasylError("coverSizeExceedsLimit") elif thumbsize > 10 * _MEGABYTE: raise WeasylError("thumbSizeExceedsLimit") if submitsize: submitextension = files.get_extension_for_category( submitfile, m.TEXT_SUBMISSION_CATEGORY) if submitextension is None: raise WeasylError("submitType") if _limit(submitsize, submitextension, premium): raise WeasylError("submitSizeExceedsLimit") submit_media_item = orm.fetch_or_create_media_item( submitfile, file_type=submitextension.lstrip('.')) check_for_duplicate_media(userid, submit_media_item.mediaid) else: submit_media_item = None thumb_media_item = media.make_cover_media_item(thumbfile) cover_media_item = media.make_cover_media_item(coverfile) if cover_media_item and not thumb_media_item: thumb_media_item = cover_media_item # Assign settings settings = [] settings.append("f" if friends_only else "") settings.append("q" if critique else "") if embedlink: settings.append('D') settings = "".join(settings) # Create submission # TODO(kailys): use ORM object db = d.connect() now = arrow.get() try: q = (d.meta.tables['submission'].insert().values([{ "folderid": submission.folderid, "userid": userid, "unixtime": now, "title": submission.title, "content": submission.content, "subtype": submission.subtype, "rating": submission.rating.code, "settings": settings, "sorttime": now, }]).returning(d.meta.tables['submission'].c.submitid)) submitid = db.scalar(q) if embedlink: q = (d.meta.tables['google_doc_embeds'].insert().values( submitid=submitid, embed_url=embedlink)) db.execute(q) except: files.clear_temporary(userid) raise # Assign search tags searchtag.associate(userid, tags, submitid=submitid) if submit_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'submission', submit_media_item, rating=submission.rating.code) if cover_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'cover', cover_media_item, rating=submission.rating.code) if thumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-source', thumb_media_item) # Create notifications if create_notifications: _create_notifications(userid, submitid, submission.rating, settings, submission.title, tags) # Clear temporary files files.clear_temporary(userid) d.metric('increment', 'submissions') d.metric('increment', 'literarysubmissions') return submitid, bool(thumb_media_item)
def create_visual(userid, submission, friends_only, tags, imageURL, thumbfile, submitfile, critique, create_notifications): premium = d.get_premium(userid) if imageURL: resp = d.http_get(imageURL, timeout=5) submitfile = resp.content # Determine filesizes thumbsize = len(thumbfile) submitsize = len(submitfile) if not submitsize: files.clear_temporary(userid) raise WeasylError("submitSizeZero") elif thumbsize > 10 * _MEGABYTE: files.clear_temporary(userid) raise WeasylError("thumbSizeExceedsLimit") im = image.from_string(submitfile) submitextension = image.image_extension(im) if _limit(submitsize, submitextension, premium): raise WeasylError("submitSizeExceedsLimit") elif submitextension not in [".jpg", ".png", ".gif"]: raise WeasylError("submitType") submit_file_type = submitextension.lstrip('.') submit_media_item = orm.fetch_or_create_media_item( submitfile, file_type=submit_file_type, im=im) check_for_duplicate_media(userid, submit_media_item.mediaid) cover_media_item = submit_media_item.ensure_cover_image(im) # Thumbnail stuff. # Always create a 'generated' thumbnail from the source image. thumb_generated = images.make_thumbnail(im) if thumb_generated is im: thumb_generated_media_item = submit_media_item else: thumb_generated_media_item = orm.fetch_or_create_media_item( thumb_generated.to_buffer(format=submit_file_type), file_type=submit_file_type, im=thumb_generated) # If requested, also create a 'custom' thumbnail. thumb_media_item = media.make_cover_media_item(thumbfile) if thumb_media_item: thumb_custom = images.make_thumbnail(image.from_string(thumbfile)) thumb_custom_media_item = orm.fetch_or_create_media_item( thumb_custom.to_buffer(format=submit_file_type), file_type=submit_file_type, im=thumb_custom) # Assign settings settings = [] settings.append("f" if friends_only else "") settings.append("q" if critique else "") settings = "".join(settings) # TODO(kailys): maintain ORM object db = d.connect() now = arrow.get() q = (d.meta.tables['submission'].insert().values([{ "folderid": submission.folderid, "userid": userid, "unixtime": now, "title": submission.title, "content": submission.content, "subtype": submission.subtype, "rating": submission.rating.code, "settings": settings, "sorttime": now, }]).returning(d.meta.tables['submission'].c.submitid)) submitid = db.scalar(q) orm.SubmissionMediaLink.make_or_replace_link(submitid, 'submission', submit_media_item) orm.SubmissionMediaLink.make_or_replace_link(submitid, 'cover', cover_media_item) orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-generated', thumb_generated_media_item) if thumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-source', thumb_media_item) orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-custom', thumb_custom_media_item) # Assign search tags searchtag.associate(userid, tags, submitid=submitid) # Create notifications if create_notifications: _create_notifications(userid, submitid, submission.rating, settings, submission.title, tags) d.metric('increment', 'submissions') d.metric('increment', 'visualsubmissions') return submitid
def is_hidden(submitid): db = d.connect() su = d.meta.tables['submission'] q = d.sa.select([su.c.settings.op('~')('h')]).where(su.c.submitid == submitid) results = db.execute(q).fetchall() return bool(results and results[0][0])
def create_visual(userid, submission, friends_only, tags, imageURL, thumbfile, submitfile, critique, create_notifications): premium = d.get_premium(userid) if imageURL: resp = d.http_get(imageURL, timeout=5) submitfile = resp.content # Determine filesizes thumbsize = len(thumbfile) submitsize = len(submitfile) if not submitsize: files.clear_temporary(userid) raise WeasylError("submitSizeZero") elif thumbsize > 10 * _MEGABYTE: files.clear_temporary(userid) raise WeasylError("thumbSizeExceedsLimit") im = image.from_string(submitfile) submitextension = image.image_extension(im) if _limit(submitsize, submitextension, premium): raise WeasylError("submitSizeExceedsLimit") elif submitextension not in [".jpg", ".png", ".gif"]: raise WeasylError("submitType") submit_file_type = submitextension.lstrip('.') submit_media_item = orm.fetch_or_create_media_item( submitfile, file_type=submit_file_type, im=im) check_for_duplicate_media(userid, submit_media_item.mediaid) cover_media_item = submit_media_item.ensure_cover_image(im) # Thumbnail stuff. # Always create a 'generated' thumbnail from the source image. thumb_generated = images.make_thumbnail(im) if thumb_generated is im: thumb_generated_media_item = submit_media_item else: thumb_generated_media_item = orm.fetch_or_create_media_item( thumb_generated.to_buffer(format=submit_file_type), file_type=submit_file_type, im=thumb_generated) # If requested, also create a 'custom' thumbnail. thumb_media_item = media.make_cover_media_item(thumbfile) if thumb_media_item: thumb_custom = images.make_thumbnail(image.from_string(thumbfile)) thumb_custom_media_item = orm.fetch_or_create_media_item( thumb_custom.to_buffer(format=submit_file_type), file_type=submit_file_type, im=thumb_custom) # Assign settings settings = [] settings.append("f" if friends_only else "") settings.append("q" if critique else "") settings = "".join(settings) # TODO(kailys): maintain ORM object db = d.connect() now = arrow.get() q = ( d.meta.tables['submission'].insert().values([{ "folderid": submission.folderid, "userid": userid, "unixtime": now, "title": submission.title, "content": submission.content, "subtype": submission.subtype, "rating": submission.rating.code, "settings": settings, "sorttime": now, }]).returning(d.meta.tables['submission'].c.submitid)) submitid = db.scalar(q) orm.SubmissionMediaLink.make_or_replace_link( submitid, 'submission', submit_media_item) orm.SubmissionMediaLink.make_or_replace_link( submitid, 'cover', cover_media_item) orm.SubmissionMediaLink.make_or_replace_link( submitid, 'thumbnail-generated', thumb_generated_media_item) if thumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-source', thumb_media_item) orm.SubmissionMediaLink.make_or_replace_link( submitid, 'thumbnail-custom', thumb_custom_media_item) # Assign search tags searchtag.associate(userid, tags, submitid=submitid) # Create notifications if create_notifications: _create_notifications(userid, submitid, submission.rating, settings, submission.title, tags) d.metric('increment', 'submissions') d.metric('increment', 'visualsubmissions') return submitid
def is_hidden(charid): db = define.connect() ch = define.meta.tables['character'] q = define.sa.select([ch.c.settings.op('~')('h')]).where(ch.c.charid == charid) results = db.execute(q).fetchall() return bool(results and results[0][0])
def edit(userid, submission, embedlink=None, friends_only=False, critique=False): query = d.execute( "SELECT userid, subtype, settings FROM submission WHERE submitid = %i", [submission.submitid], ["single"]) if not query or "h" in query[2]: raise WeasylError("Unexpected") elif "a" in query[2] and userid not in staff.MODS: raise WeasylError("AdminLocked") elif userid != query[0] and userid not in staff.MODS: raise WeasylError("InsufficientPermissions") elif not submission.title: raise WeasylError("titleInvalid") elif not submission.rating: raise WeasylError("Unexpected") elif not folder.check(query[0], submission.folderid): raise WeasylError("Unexpected") elif submission.subtype / 1000 != query[1] / 1000: raise WeasylError("Unexpected") elif 'v' in query[2] and not embed.check_valid(embedlink): raise WeasylError("embedlinkInvalid") elif 'D' in query[2]: check_google_doc_embed_data(embedlink) profile.check_user_rating_allowed(userid, submission.rating) # Assign settings settings = [query[2].replace("f", "").replace("q", "")] settings.append("f" if friends_only else "") settings.append("q" if critique else "") settings = "".join(settings) if "v" in settings: submission.content = "%s\n%s" % (embedlink, submission.content) if "f" in settings: welcome.submission_became_friends_only(submission.submitid, userid) # TODO(kailys): maintain ORM object db = d.connect() su = d.meta.tables['submission'] q = ( su.update() .values( folderid=submission.folderid, title=submission.title, content=submission.content, subtype=submission.subtype, rating=submission.rating, settings=settings, ) .where(su.c.submitid == submission.submitid)) db.execute(q) if 'D' in settings: db = d.connect() gde = d.meta.tables['google_doc_embeds'] q = (gde.update() .values(embed_url=embedlink) .where(gde.c.submitid == submission.submitid)) db.execute(q) if userid != query[0]: from weasyl import moderation moderation.note_about( userid, query[0], 'The following submission was edited:', '- ' + text.markdown_link(submission.title, '/submission/%s?anyway=true' % (submission.submitid,)))
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), }
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, }
def create_multimedia(userid, submission, embedlink=None, friends_only=None, tags=None, coverfile=None, thumbfile=None, submitfile=None, critique=False, create_notifications=True, auto_thumb=False): premium = d.get_premium(userid) embedlink = embedlink.strip() # Determine filesizes coversize = len(coverfile) thumbsize = len(thumbfile) submitsize = len(submitfile) if not submitsize and not embedlink: raise WeasylError("submitSizeZero") elif embedlink and not embed.check_valid(embedlink): raise WeasylError("embedlinkInvalid") elif coversize > 10 * _MEGABYTE: raise WeasylError("coverSizeExceedsLimit") elif thumbsize > 10 * _MEGABYTE: raise WeasylError("thumbSizeExceedsLimit") if submitsize: submitextension = files.get_extension_for_category(submitfile, m.MULTIMEDIA_SUBMISSION_CATEGORY) if submitextension is None: raise WeasylError("submitType") elif submitextension not in [".mp3", ".swf"] and not embedlink: raise WeasylError("submitType") elif _limit(submitsize, submitextension, premium): raise WeasylError("submitSizeExceedsLimit") submit_media_item = orm.fetch_or_create_media_item( submitfile, file_type=submitextension.lstrip('.')) check_for_duplicate_media(userid, submit_media_item.mediaid) else: submit_media_item = None thumb_media_item = media.make_cover_media_item(thumbfile) cover_media_item = media.make_cover_media_item(coverfile) if cover_media_item and not thumb_media_item: thumb_media_item = cover_media_item tempthumb_media_item = None im = None if auto_thumb: if thumbsize == 0 and coversize == 0: # Fetch default thumbnail from source if available thumb_url = embed.thumbnail(embedlink) if thumb_url: resp = d.http_get(thumb_url, timeout=5) im = image.from_string(resp.content) if not im and (thumbsize or coversize): im = image.from_string(thumbfile or coverfile) if im: tempthumb = images.make_thumbnail(im) tempthumb_type = images.image_file_type(tempthumb) tempthumb_media_item = orm.fetch_or_create_media_item( tempthumb.to_buffer(format=tempthumb_type), file_type=tempthumb_type, im=tempthumb) # Assign settings settings = [] settings.append("f" if friends_only else "") settings.append("q" if critique else "") settings.append("v" if embedlink else "") settings = "".join(settings) # Inject embedlink if embedlink: submission.content = "".join([embedlink, "\n", submission.content]) # Create submission db = d.connect() now = arrow.get() try: q = ( d.meta.tables['submission'].insert().values([{ "folderid": submission.folderid, "userid": userid, "unixtime": now, "title": submission.title, "content": submission.content, "subtype": submission.subtype, "rating": submission.rating, "settings": settings, "sorttime": now, }]) .returning(d.meta.tables['submission'].c.submitid)) submitid = db.scalar(q) except PostgresError: files.clear_temporary(userid) raise # Assign search tags searchtag.associate(userid, tags, submitid=submitid) if submit_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'submission', submit_media_item, rating=submission.rating.code) if cover_media_item: orm.SubmissionMediaLink.make_or_replace_link( submitid, 'cover', cover_media_item, rating=submission.rating.code) if thumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-source', thumb_media_item) if tempthumb_media_item: orm.SubmissionMediaLink.make_or_replace_link(submitid, 'thumbnail-custom', tempthumb_media_item) # Create notifications if create_notifications: _create_notifications(userid, submitid, submission.rating, settings, submission.title, tags) # Clear temporary files files.clear_temporary(userid) d.metric('increment', 'submissions') d.metric('increment', 'multimediasubmissions') return submitid, bool(thumb_media_item)
def edit(userid, submission, embedlink=None, friends_only=False, critique=False): query = d.execute( "SELECT userid, subtype, settings FROM submission WHERE submitid = %i", [submission.submitid], ["single"]) if not query or "h" in query[2]: raise WeasylError("Unexpected") elif "a" in query[2] and userid not in staff.MODS: raise WeasylError("AdminLocked") elif userid != query[0] and userid not in staff.MODS: raise WeasylError("InsufficientPermissions") elif not submission.title: raise WeasylError("titleInvalid") elif not submission.rating: raise WeasylError("Unexpected") elif not folder.check(query[0], submission.folderid): raise WeasylError("Unexpected") elif submission.subtype / 1000 != query[1] / 1000: raise WeasylError("Unexpected") elif 'v' in query[2] and not embed.check_valid(embedlink): raise WeasylError("embedlinkInvalid") elif 'D' in query[2]: check_google_doc_embed_data(embedlink) profile.check_user_rating_allowed(userid, submission.rating) # Assign settings settings = [query[2].replace("f", "").replace("q", "")] settings.append("f" if friends_only else "") settings.append("q" if critique else "") settings = "".join(settings) if "v" in settings: submission.content = "%s\n%s" % (embedlink, submission.content) if "f" in settings: welcome.submission_became_friends_only(submission.submitid, userid) # TODO(kailys): maintain ORM object db = d.connect() su = d.meta.tables['submission'] q = (su.update().values( folderid=submission.folderid, title=submission.title, content=submission.content, subtype=submission.subtype, rating=submission.rating, settings=settings, ).where(su.c.submitid == submission.submitid)) db.execute(q) if 'D' in settings: db = d.connect() gde = d.meta.tables['google_doc_embeds'] q = (gde.update().values(embed_url=embedlink).where( gde.c.submitid == submission.submitid)) db.execute(q) if userid != query[0]: from weasyl import moderation moderation.note_about( userid, query[0], 'The following submission was edited:', '- ' + text.markdown_link( submission.title, '/submission/%s?anyway=true' % (submission.submitid, )))
def bulk_edit(userid, action, submissions=(), characters=(), journals=()): web.header('Content-Type', 'text/plain') if not submissions and not characters and not journals or action == 'null': return 'Nothing to do.' if action == 'show': # Unhide (show/make visible) a submission def action(tbl): return (tbl.update().values( settings=sa.func.replace(tbl.c.settings, 'h', '')).where( tbl.c.settings.op('~')('h'))) action_string = 'unhidden' provide_link = True elif action == 'hide': # Hide a submission from public view def action(tbl): return (tbl.update().values( settings=tbl.c.settings.op('||')('h')).where( tbl.c.settings.op('!~')('h'))) action_string = 'hidden' # There's no value in giving the user a link to the submission as they # won't be able to see it. provide_link = False elif action.startswith('rate-'): # Re-rate a submission _, _, rating = action.partition('-') rating = int(rating) def action(tbl): return (tbl.update().values(rating=rating).where( tbl.c.rating != rating)) action_string = 'rerated ' + ratings.CODE_TO_NAME[rating] provide_link = True elif action == 'clearcritique': # Clear the "critique requested" flag def action(tbl): return (tbl.update().values( settings=sa.func.replace(tbl.c.settings, 'q', '')).where( tbl.c.settings.op('~')('q'))) action_string = 'unmarked as "critique requested"' provide_link = True elif action == 'setcritique': # Set the "critique requested" flag def action(tbl): return (tbl.update().values( settings=tbl.c.settings.op('||')('q')).where( tbl.c.settings.op('!~')('q'))) action_string = 'marked as "critique requested"' provide_link = True else: raise WeasylError('Unexpected') db = d.connect() affected = collections.defaultdict(list) copyable = [] for (tbl, col, title_col, urlpart), values in zip(_tables, [submissions, characters, journals]): if values: results = db.execute( action(tbl).where(tbl.c[col].in_(values)).returning( tbl.c[col], tbl.c[title_col], tbl.c.userid)) for thingid, title, ownerid in results: affected[ownerid].append('- ' + text.markdown_link( title, '/%s/%s?anyway=true' % (urlpart, thingid))) if provide_link: copyable.append( '- ' + text.markdown_link(title, '/%s/%s' % (urlpart, thingid))) else: copyable.append('- %s' % (title, )) now = arrow.utcnow() values = [] for target, target_affected in affected.iteritems(): staff_note = '## The following items were %s:\n\n%s' % ( action_string, '\n'.join(target_affected)) values.append({ 'userid': userid, 'target_user': target, 'unixtime': now, 'settings': 's', 'content': staff_note, }) if values: db.execute(d.meta.tables['comments'].insert().values(values)) return 'Affected items (%s): \n\n%s' % (action_string, '\n'.join(copyable))
def bulk_edit(userid, action, submissions=(), characters=(), journals=()): web.header('Content-Type', 'text/plain') if not submissions and not characters and not journals or action == 'null': return 'Nothing to do.' if action == 'show': # Unhide (show/make visible) a submission def action(tbl): return ( tbl.update() .values(settings=sa.func.replace(tbl.c.settings, 'h', '')) .where(tbl.c.settings.op('~')('h'))) action_string = 'unhidden' provide_link = True elif action == 'hide': # Hide a submission from public view def action(tbl): return ( tbl.update() .values(settings=tbl.c.settings.op('||')('h')) .where(tbl.c.settings.op('!~')('h'))) action_string = 'hidden' # There's no value in giving the user a link to the submission as they # won't be able to see it. provide_link = False elif action.startswith('rate-'): # Re-rate a submission _, _, rating = action.partition('-') rating = int(rating) def action(tbl): return ( tbl.update() .values(rating=rating) .where(tbl.c.rating != rating)) action_string = 'rerated ' + ratings.CODE_TO_NAME[rating] provide_link = True elif action == 'clearcritique': # Clear the "critique requested" flag def action(tbl): return ( tbl.update() .values(settings=sa.func.replace(tbl.c.settings, 'q', '')) .where(tbl.c.settings.op('~')('q'))) action_string = 'unmarked as "critique requested"' provide_link = True elif action == 'setcritique': # Set the "critique requested" flag def action(tbl): return ( tbl.update() .values(settings=tbl.c.settings.op('||')('q')) .where(tbl.c.settings.op('!~')('q'))) action_string = 'marked as "critique requested"' provide_link = True else: raise WeasylError('Unexpected') db = d.connect() affected = collections.defaultdict(list) copyable = [] for (tbl, col, title_col, urlpart), values in zip(_tables, [submissions, characters, journals]): if values: results = db.execute( action(tbl) .where(tbl.c[col].in_(values)) .returning(tbl.c[col], tbl.c[title_col], tbl.c.userid)) for thingid, title, ownerid in results: affected[ownerid].append('- ' + text.markdown_link(title, '/%s/%s?anyway=true' % (urlpart, thingid))) if provide_link: copyable.append('- ' + text.markdown_link(title, '/%s/%s' % (urlpart, thingid))) else: copyable.append('- %s' % (title,)) now = arrow.utcnow() values = [] for target, target_affected in affected.iteritems(): staff_note = '## The following items were %s:\n\n%s' % (action_string, '\n'.join(target_affected)) values.append({ 'userid': userid, 'target_user': target, 'unixtime': now, 'settings': 's', 'content': staff_note, }) if values: db.execute(d.meta.tables['comments'].insert().values(values)) return 'Affected items (%s): \n\n%s' % (action_string, '\n'.join(copyable))