def GET(self, name=""): form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's journals" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(self.user_id, title=page_title) page.append(define.render(template.user_journals, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Journals list # TODO(weykent): use select_user_list journal.select_list(self.user_id, rating, 250, otherid=otherid, config=config), # Latest journal journal.select_latest(self.user_id, rating, otherid=otherid), ])) return define.common_page_end(self.user_id, page)
def journals_(request): form = request.web_input(userid="", name="", backid=None, nextid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) config = define.get_config(request.userid) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response(define.errorpage(request.userid, errorcode.no_guest_access)) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's journals" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(request.userid, title=page_title) page.append(define.render('user/journals.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Journals list # TODO(weykent): use select_user_list journal.select_list(request.userid, rating, 250, otherid=otherid, config=config), # Latest journal journal.select_latest(request.userid, rating, otherid=otherid), ])) return Response(define.common_page_end(request.userid, page))
def collections_(request): form = request.web_input(userid="", name="", backid=None, nextid=None, folderid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) config = define.get_config(request.userid) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response( define.errorpage(request.userid, errorcode.no_guest_access)) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's collections" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(request.userid, title=page_title) url_format = "/collections?userid={userid}&%s".format( userid=userprofile['userid']) result = pagination.PaginatedResult(collection.select_list, collection.select_count, 'submitid', url_format, request.userid, rating, 66, otherid=otherid, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid), config=config) page.append( define.render( 'user/collections.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Collections result, ])) return Response(define.common_page_end(request.userid, page))
def GET(self, name=""): form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's characters" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(self.user_id, title=page_title) url_format = "/characters?userid={userid}&%s".format( userid=userprofile['userid']) result = pagination.PaginatedResult(character.select_list, character.select_count, 'charid', url_format, self.user_id, rating, 60, otherid=otherid, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid), config=config) page.append( define.render( template.user_characters, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Characters list result, ])) return define.common_page_end(self.user_id, page)
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
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"]), }
def journals_(request): name = request.matchdict.get('name', request.params.get('name', '')) userid = define.get_int(request.params.get('userid')) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, userid, name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): raise WeasylError('noGuests') userprofile = profile.select_profile(otherid, viewer=request.userid) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's journals" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(request.userid, title=page_title) page.append( define.render( 'user/journals.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Journals list journal.select_list(request.userid, rating, otherid=otherid), ])) return Response(define.common_page_end(request.userid, page))
def followed_(request): name = request.matchdict.get('name', request.params.get('name', '')) userid = define.get_int(request.params.get('userid')) otherid = profile.resolve(request.userid, userid, name) backid = request.params.get('backid') nextid = request.params.get('nextid') if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): raise WeasylError('noGuests') userprofile = profile.select_profile(otherid, viewer=request.userid) return Response( define.webpage( request.userid, "user/followed.html", [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Followed followuser.select_followed(request.userid, otherid, limit=44, backid=define.get_int(backid), nextid=define.get_int(nextid)), ]))
def select_list(userid, rating, limit, otherid=None, pending=False, backid=None, nextid=None, config=None, options=[]): if config is None: config = d.get_config(userid) statement = ["SELECT su.submitid, su.title, su.subtype, su.rating, co.unixtime, " "su.userid, pr.username, cpr.username, cpr.userid "] statement.extend(select_query(userid, rating, otherid, pending, backid, nextid, config)) statement.append(" ORDER BY co.unixtime%s LIMIT %i" % ("" if backid else " DESC", limit)) query = [] for i in d.execute("".join(statement)): query.append({ "contype": 10, "collection": True, "submitid": i[0], "title": i[1], "subtype": i[2], "rating": i[3], "unixtime": i[4], "userid": i[5], "username": i[6], # username of creator "collector": i[7], # username of collector "collectorid": i[8], "sub_media": media.get_submission_media(i[0]), }) return query[::-1] if backid else query
def followed_(request): cachename = "user/followed.html" form = request.web_input(userid="", name="", backid=None, nextid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response(define.errorpage(request.userid, errorcode.no_guest_access)) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) return Response(define.webpage(request.userid, cachename, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Followed followuser.select_followed(request.userid, otherid, limit=44, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid)), ]))
def GET(self, name=""): now = time.time() form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's shouts" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(self.user_id, title=page_title) page.append(define.render(template.user_shouts, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Myself profile.select_myself(self.user_id), # Comments shout.select(self.user_id, ownerid=otherid), # Feature "shouts", ])) return define.common_page_end(self.user_id, page, now=now)
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
def shouts_(request): form = request.web_input(userid="", name="", backid=None, nextid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response(define.errorpage(request.userid, errorcode.no_guest_access)) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's shouts" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(request.userid, title=page_title) page.append(define.render('user/shouts.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Myself profile.select_myself(request.userid), # Comments shout.select(request.userid, ownerid=otherid), # Feature "shouts", ])) return Response(define.common_page_end(request.userid, page))
def GET(self, name=""): cachename = "user/followed.html" form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) return define.webpage( self.user_id, cachename, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Followed followuser.select_followed(self.user_id, otherid, limit=44, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid)), ])
def GET(self, name=""): cachename = "user/followed.html" form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) return define.webpage(self.user_id, cachename, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Followed followuser.select_followed(self.user_id, otherid, limit=44, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid)), ])
def following_(request): form = request.web_input(userid="", name="", backid=None, nextid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): raise WeasylError('noGuests') userprofile = profile.select_profile(otherid, viewer=request.userid) return Response( define.webpage( request.userid, "user/following.html", [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Following followuser.select_following(request.userid, otherid, limit=44, backid=define.get_int(form.backid), nextid=define.get_int( form.nextid)), ]))
def submissions_(request): name = request.matchdict.get('name', request.params.get('name', '')) userid = define.get_int(request.params.get('userid')) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, userid, name) folderid = define.get_int(request.params.get('folderid')) or None backid = request.params.get('backid') nextid = request.params.get('nextid') if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): raise WeasylError('noGuests') userprofile = profile.select_profile(otherid, viewer=request.userid) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's submissions" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(request.userid, title=page_title) url_format = "/submissions/{username}?%s{folderquery}".format( username=define.get_sysname(userprofile['username']), folderquery="&folderid=%d" % folderid if folderid else "") result = pagination.PaginatedResult(submission.select_list, submission.select_count, 'submitid', url_format, request.userid, rating, limit=60, otherid=otherid, folderid=folderid, backid=define.get_int(backid), nextid=define.get_int(nextid), profile_page_filter=not folderid) page.append( define.render( 'user/submissions.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Recent submissions result, # Folders folder.select_list(otherid), # Current folder folderid, ])) return Response(define.common_page_end(request.userid, page))
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_query(userid, rating, otherid=None, folderid=None, backid=None, nextid=None, subcat=None, exclude=None, options=[], config=None, profile_page_filter=False, index_page_filter=False, featured_filter=False): if config is None: config = d.get_config(userid) statement = [ "FROM submission su " "INNER JOIN profile pr ON su.userid = pr.userid " "LEFT JOIN folder f USING (folderid) " "WHERE su.settings !~ 'h'"] if profile_page_filter: statement.append(" AND COALESCE(f.settings !~ 'u', true)") if index_page_filter: statement.append(" AND COALESCE(f.settings !~ 'm', true)") if featured_filter: statement.append(" AND COALESCE(f.settings ~ 'f', false)") # Logged in users will see their own submissions regardless of rating # EXCEPT if they are in SFW mode if userid and not d.is_sfw_mode(): statement.append(" AND (su.rating <= %i OR su.userid = %i)" % (rating, userid)) else: statement.append(" AND su.rating <= %i" % (rating,)) if otherid: statement.append(" AND su.userid = %i" % (otherid,)) if folderid: statement.append(" AND su.folderid = %i" % (folderid,)) if exclude: statement.append(" AND su.submitid != %i" % (exclude,)) if subcat: statement.append(" AND su.subtype >= %i AND su.subtype < %i" % (subcat, subcat + 1000)) if "critique" in options: statement.append(" AND su.settings ~ 'q' AND su.unixtime > %i" % (d.get_time() - 259200,)) if backid: statement.append(" AND su.submitid > %i" % (backid,)) elif nextid: statement.append(" AND su.submitid < %i" % (nextid,)) elif "offset" in options: statement.append(" AND su.unixtime < %i" % (d.get_time() - 1800,)) if userid: statement.append(m.MACRO_FRIENDUSER_SUBMIT % (userid, userid, userid)) if not otherid: statement.append(m.MACRO_IGNOREUSER % (userid, "su")) statement.append(m.MACRO_BLOCKTAG_SUBMIT % (userid, userid)) else: statement.append(" AND su.settings !~ 'f'") return statement
def select_user_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.userid, pr.username, pr.config, jo.rating, jo.unixtime" " FROM journal jo" " JOIN profile pr ON jo.userid = pr.userid" " WHERE jo.settings !~ 'h'" ] if otherid: statement.append(" AND jo.userid = %i") if userid: # filter own content in SFW mode if d.is_sfw_mode(): statement.append(" AND (jo.rating <= %i)" % (rating, )) else: statement.append(" AND (jo.userid = %i OR jo.rating <= %i)" % (userid, rating)) statement.append(m.MACRO_FRIENDUSER_JOURNAL % (userid, userid, userid)) if not otherid: statement.append(m.MACRO_IGNOREUSER % (userid, "jo")) statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid)) else: statement.append(" AND jo.rating <= %i AND jo.settings !~ 'f'" % (rating, )) if backid: statement.append(" AND jo.journalid > %i" % backid) elif nextid: statement.append(" AND jo.journalid < %i" % nextid) statement.append(" ORDER BY jo.journalid%s LIMIT %i" % ("" if backid else " DESC", limit)) query = [{ "contype": 30, "journalid": i[0], "title": i[1], "userid": i[2], "username": i[3], "rating": i[5], "unixtime": i[6], } for i in d.execute("".join(statement))] media.populate_with_user_media(query) return query[::-1] if backid else query
def GET(self, name=""): form = web.input(userid="", name="", backid=None, nextid=None, folderid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) otherid = profile.resolve(self.user_id, form.userid, form.name) folderid = define.get_int(form.folderid) or None if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's submissions" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(self.user_id, title=page_title) url_format = "/submissions/{username}?%s{folderquery}".format( username=define.get_sysname(userprofile['username']), folderquery="&folderid=%d" % folderid if folderid else "") result = pagination.PaginatedResult( submission.select_list, submission.select_count, 'submitid', url_format, self.user_id, rating, 60, otherid=otherid, folderid=folderid, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid), config=config, profile_page_filter=not folderid) page.append(define.render(template.user_submissions, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Recent submissions result, # Folders folder.select_list(otherid, "sidebar/all"), # Current folder folderid, ])) return define.common_page_end(self.user_id, page)
def submissions_(request): form = request.web_input(userid="", name="", backid=None, nextid=None, folderid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) config = define.get_config(request.userid) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, form.userid, form.name) folderid = define.get_int(form.folderid) or None if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response(define.errorpage(request.userid, errorcode.no_guest_access)) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's submissions" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(request.userid, title=page_title) url_format = "/submissions/{username}?%s{folderquery}".format( username=define.get_sysname(userprofile['username']), folderquery="&folderid=%d" % folderid if folderid else "") result = pagination.PaginatedResult( submission.select_list, submission.select_count, 'submitid', url_format, request.userid, rating, 60, otherid=otherid, folderid=folderid, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid), config=config, profile_page_filter=not folderid) page.append(define.render('user/submissions.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Recent submissions result, # Folders folder.select_list(otherid, "sidebar/all"), # Current folder folderid, ])) return Response(define.common_page_end(request.userid, page))
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_near(userid, rating, limit, otherid, folderid, submitid, config=None): if config is None: config = d.get_config(userid) statement = [ """ SELECT su.submitid, su.title, su.rating, su.unixtime, su.userid, pr.username, su.settings, su.subtype FROM submission su INNER JOIN profile pr ON su.userid = pr.userid WHERE su.userid = %i AND su.settings !~ 'h' """ % (otherid, ) ] if userid: # Users always see their own content. statement.append(" AND (su.rating <= %i OR su.userid = %i)" % (rating, userid)) statement.append(m.MACRO_IGNOREUSER % (userid, "su")) statement.append(m.MACRO_FRIENDUSER_SUBMIT % (userid, userid, userid)) statement.append(m.MACRO_BLOCKTAG_SUBMIT % (userid, userid)) else: statement.append(" AND su.rating <= %i AND su.settings !~ 'f'" % (rating, )) if folderid: statement.append(" AND su.folderid = %i" % folderid) query = [{ "contype": 10, "submitid": i[0], "title": i[1], "rating": i[2], "unixtime": i[3], "userid": i[4], "username": i[5], "subtype": i[7], } for i in d.execute("".join(statement))] query.sort(key=lambda i: i['submitid']) older = [i for i in query if i["submitid"] < submitid][-limit:] newer = [i for i in query if i["submitid"] > submitid][:limit] media.populate_with_submission_media(older + newer) return { "older": older, "newer": newer, }
def shouts_(request): form = request.web_input(userid="", name="", backid=None, nextid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): raise WeasylError('noGuests') userprofile = profile.select_profile(otherid, viewer=request.userid) if otherid != request.userid and not define.is_vouched_for(otherid): can_vouch = request.userid != 0 and define.is_vouched_for( request.userid) return Response( define.webpage( request.userid, "error/unverified.html", [request, otherid, userprofile['username'], can_vouch], ), status=403, ) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's shouts" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(request.userid, title=page_title) page.append( define.render( 'user/shouts.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Myself profile.select_myself(request.userid), # Comments shout.select(request.userid, ownerid=otherid), # Feature "shouts", ])) return Response(define.common_page_end(request.userid, page))
def select_char(userid, rating, limit, otherid=None, backid=None, nextid=None, config=None): if config is None: config = d.get_config(userid) query = [] statement = [""" SELECT ch.charid, ch.char_name, ch.rating, fa.unixtime, ch.userid, pr.username, ch.settings FROM favorite fa INNER JOIN character ch ON fa.targetid = ch.charid INNER JOIN profile pr ON ch.userid = pr.userid WHERE fa.type = 'f' AND ch.settings !~ 'h' """] if userid: # filter own content in SFW mode if d.is_sfw_mode(): statement.append(" AND (ch.rating <= %i)" % (rating,)) else: statement.append(" AND (ch.userid = %i OR ch.rating <= %i)" % (userid, rating)) statement.append(m.MACRO_FRIENDUSER_CHARACTER % (userid, userid, userid)) statement.append(m.MACRO_IGNOREUSER % (userid, "ch")) statement.append(m.MACRO_BLOCKTAG_CHAR % (userid, userid)) else: statement.append(" AND ch.rating <= %i AND ch.settings !~ 'f'" % (rating,)) if otherid: statement.append(" AND fa.userid = %i" % (otherid,)) if backid: statement.append(" AND fa.unixtime > " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 'f'))" % (otherid, backid)) elif nextid: statement.append(" AND fa.unixtime < " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 'f'))" % (otherid, nextid)) statement.append(" ORDER BY fa.unixtime%s LIMIT %i" % ("" if backid else " DESC", limit)) from weasyl import character query = [{ "contype": 20, "charid": i[0], "title": i[1], "rating": i[2], "unixtime": i[3], "userid": i[4], "username": i[5], "sub_media": character.fake_media_items(i[0], i[4], d.get_sysname(i[5]), i[6]), } for i in d.execute("".join(statement))] return query[::-1] if backid else query
def GET(self, name=""): form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's characters" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(self.user_id, title=page_title) url_format = "/characters?userid={userid}&%s".format(userid=userprofile['userid']) result = pagination.PaginatedResult( character.select_list, character.select_count, 'charid', url_format, self.user_id, rating, 60, otherid=otherid, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid), config=config) page.append(define.render(template.user_characters, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Characters list result, ])) return define.common_page_end(self.user_id, page)
def select_journal(userid, rating, limit, otherid=None, backid=None, nextid=None, config=None): if config is None: config = d.get_config(userid) query = [] statement = [""" SELECT jo.journalid, jo.title, jo.rating, fa.unixtime, jo.userid, pr.username, pr.config FROM favorite fa INNER JOIN journal jo ON fa.targetid = jo.journalid INNER JOIN profile pr ON jo.userid = pr.userid WHERE fa.type = 'j' AND jo.settings !~ 'h' """] if userid: # filter own content in SFW mode if d.is_sfw_mode(): statement.append(" AND (jo.rating <= %i)" % (rating,)) else: statement.append(" AND (jo.userid = %i OR jo.rating <= %i)" % (userid, rating)) statement.append(m.MACRO_FRIENDUSER_JOURNAL % (userid, userid, userid)) statement.append(m.MACRO_IGNOREUSER % (userid, "jo")) statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid)) else: statement.append(" AND jo.rating <= %i AND jo.settings !~ 'f'" % (rating,)) if otherid: statement.append(" AND fa.userid = %i" % (otherid,)) if backid: statement.append(" AND fa.unixtime > " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 'j'))" % (otherid, backid)) elif nextid: statement.append(" AND fa.unixtime < " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 'j'))" % (otherid, nextid)) statement.append(" ORDER BY fa.unixtime%s LIMIT %i" % ("" if backid else " DESC", limit)) query = [{ "contype": 30, "journalid": i[0], "title": i[1], "rating": i[2], "unixtime": i[3], "userid": i[4], "username": i[5], } for i in d.execute("".join(statement))] media.populate_with_user_media(query) return query[::-1] if backid else query
def collections_(request): name = request.matchdict.get('name', request.params.get('name', '')) userid = define.get_int(request.params.get('userid')) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, userid, name) backid = request.params.get('backid') nextid = request.params.get('nextid') if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): raise WeasylError('noGuests') userprofile = profile.select_profile(otherid, viewer=request.userid) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's collections" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(request.userid, title=page_title) url_format = "/collections?userid={userid}&%s".format( userid=userprofile['userid']) result = pagination.PaginatedResult(collection.select_list, collection.select_count, 'submitid', url_format, request.userid, rating, limit=66, otherid=otherid, backid=define.get_int(backid), nextid=define.get_int(nextid)) page.append( define.render( 'user/collections.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Collections result, ])) return Response(define.common_page_end(request.userid, page))
def insert(userid, otherid): if ignoreuser.check(otherid, userid): raise WeasylError("IgnoredYou") elif ignoreuser.check(userid, otherid): raise WeasylError("YouIgnored") d.engine.execute( 'INSERT INTO watchuser (userid, otherid, settings) VALUES (%(user)s, %(other)s, %(settings)s) ' 'ON CONFLICT DO NOTHING', user=userid, other=otherid, settings=WatchSettings.from_code(d.get_config(userid)).to_code()) from weasyl import welcome welcome.followuser_remove(userid, otherid) welcome.followuser_insert(userid, otherid)
def collections_(request): form = request.web_input(userid="", name="", backid=None, nextid=None, folderid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) config = define.get_config(request.userid) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response(define.errorpage(request.userid, errorcode.no_guest_access)) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's collections" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(request.userid, title=page_title) url_format = "/collections?userid={userid}&%s".format(userid=userprofile['userid']) result = pagination.PaginatedResult( collection.select_list, collection.select_count, 'submitid', url_format, request.userid, rating, 66, otherid=otherid, backid=define.get_int(form.backid), nextid=define.get_int(form.nextid), config=config) page.append(define.render('user/collections.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Collections result, ])) return Response(define.common_page_end(request.userid, page))
def template_fields(userid): config = d.get_config(userid) rating = d.get_rating(userid) submissions = list(filter_submissions(userid, recent_submissions())) ret = partition_submissions(submissions) return ret + [ # Recent site news update siteupdate.select(), # Recent critique submissions submission.select_list(userid, rating, 4, options=["critique"], config=config), # Currently streaming users profile.select_streaming(userid, rating, 4), # Recently popular submissions list(itertools.islice(filter_submissions(userid, submission.select_recently_popular(), incidence_limit=1), 11)), ]
def template_fields(userid): config = d.get_config(userid) rating = d.get_rating(userid) submissions = list(filter_submissions(userid, recent_submissions())) ret = partition_submissions(submissions) return ret + [ # Recent site news update siteupdate.select_last(), # Recent critique submissions submission.select_list(userid, rating, 4, options=["critique"], config=config), # Currently streaming users profile.select_streaming(userid, rating, 4), # Recently popular submissions list(itertools.islice(filter_submissions(userid, submission.select_recently_popular(), incidence_limit=1), 11)), ]
def select_user_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.userid, pr.username, pr.config, jo.rating, jo.unixtime" " FROM journal jo" " JOIN profile pr ON jo.userid = pr.userid" " WHERE jo.settings !~ 'h'"] if otherid: statement.append(" AND jo.userid = %i") if userid: # filter own content in SFW mode if d.is_sfw_mode(): statement.append(" AND (jo.rating <= %i)" % (rating,)) else: statement.append(" AND (jo.userid = %i OR jo.rating <= %i)" % (userid, rating)) statement.append(m.MACRO_FRIENDUSER_JOURNAL % (userid, userid, userid)) if not otherid: statement.append(m.MACRO_IGNOREUSER % (userid, "jo")) statement.append(m.MACRO_BLOCKTAG_JOURNAL % (userid, userid)) else: statement.append(" AND jo.rating <= %i AND jo.settings !~ 'f'" % (rating,)) if backid: statement.append(" AND jo.journalid > %i" % backid) elif nextid: statement.append(" AND jo.journalid < %i" % nextid) statement.append(" ORDER BY jo.journalid%s LIMIT %i" % ("" if backid else " DESC", limit)) query = [{ "contype": 30, "journalid": i[0], "title": i[1], "userid": i[2], "username": i[3], "rating": i[5], "unixtime": i[6], } for i in d.execute("".join(statement))] media.populate_with_user_media(query) return query[::-1] if backid else query
def select_submit_query(userid, rating, otherid=None, backid=None, nextid=None, config=None): if config is None: config = d.get_config(userid) statement = [ " FROM favorite fa INNER JOIN" " submission su ON fa.targetid = su.submitid" " INNER JOIN profile pr ON su.userid = pr.userid" " WHERE fa.type = 's' AND su.settings !~ 'h'" ] if userid: # filter own content in SFW mode if d.is_sfw_mode(): statement.append(" AND (su.rating <= %i)" % (rating, )) else: statement.append(" AND (su.userid = %i OR su.rating <= %i)" % (userid, rating)) statement.append(m.MACRO_IGNOREUSER % (userid, "su")) statement.append(m.MACRO_BLOCKTAG_SUBMIT % (userid, userid)) statement.append(m.MACRO_FRIENDUSER_SUBMIT % (userid, userid, userid)) else: statement.append(" AND su.rating <= %i" % (rating, )) statement.append(" AND su.settings !~ 'f'") if otherid: statement.append(" AND fa.userid = %i" % otherid) if backid: statement.append( " AND fa.unixtime > " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 's'))" % (otherid, backid)) elif nextid: statement.append( " AND fa.unixtime < " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 's'))" % (otherid, nextid)) return statement
def select_near(userid, rating, limit, otherid, folderid, submitid, config=None): if config is None: config = d.get_config(userid) statement = [""" SELECT su.submitid, su.title, su.rating, su.unixtime, su.userid, pr.username, su.settings, su.subtype FROM submission su INNER JOIN profile pr ON su.userid = pr.userid WHERE su.userid = %i AND su.settings !~ 'h' """ % (otherid,)] if userid: # Users always see their own content. statement.append(" AND (su.rating <= %i OR su.userid = %i)" % (rating, userid)) statement.append(m.MACRO_IGNOREUSER % (userid, "su")) statement.append(m.MACRO_FRIENDUSER_SUBMIT % (userid, userid, userid)) statement.append(m.MACRO_BLOCKTAG_SUBMIT % (userid, userid)) else: statement.append(" AND su.rating <= %i AND su.settings !~ 'f'" % (rating,)) if folderid: statement.append(" AND su.folderid = %i" % folderid) query = [{ "contype": 10, "submitid": i[0], "title": i[1], "rating": i[2], "unixtime": i[3], "userid": i[4], "username": i[5], "subtype": i[7], } for i in d.execute("".join(statement))] query.sort(key=lambda i: i['submitid']) older = [i for i in query if i["submitid"] < submitid][-limit:] newer = [i for i in query if i["submitid"] > submitid][:limit] media.populate_with_submission_media(older + newer) return { "older": older, "newer": newer, }
def control_editpreferences_get_(request): config = define.get_config(request.userid) current_rating, current_sfw_rating = define.get_config_rating(request.userid) age = profile.get_user_age(request.userid) allowed_ratings = ratings.get_ratings_for_age(age) jsonb_settings = define.get_profile_settings(request.userid) return Response(define.webpage(request.userid, "control/edit_preferences.html", [ # Config config, jsonb_settings, # Rating current_rating, current_sfw_rating, age, allowed_ratings, request.weasyl_session.timezone.timezone, define.timezones(), ]))
def GET(self): config = define.get_config(self.user_id) current_rating, current_sfw_rating = define.get_config_rating(self.user_id) age = profile.get_user_age(self.user_id) allowed_ratings = ratings.get_ratings_for_age(age) jsonb_settings = define.get_profile_settings(self.user_id) return define.webpage(self.user_id, "control/edit_preferences.html", [ # Config config, jsonb_settings, # Rating current_rating, current_sfw_rating, age, allowed_ratings, web.ctx.weasyl_session.timezone.timezone, define.timezones(), ])
def control_editpreferences_get_(request): config = define.get_config(request.userid) current_rating, current_sfw_rating = define.get_config_rating(request.userid) age = profile.get_user_age(request.userid) allowed_ratings = ratings.get_ratings_for_age(age) jsonb_settings = define.get_profile_settings(request.userid) return Response(define.webpage(request.userid, "control/edit_preferences.html", [ # Config config, jsonb_settings, # Rating current_rating, current_sfw_rating, age, allowed_ratings, request.weasyl_session.timezone.timezone, define.timezones(), ], title="Site Preferences"))
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"]), }
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
def GET(self, name=""): now = time.time() form = web.input(userid="", name="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile[ 'full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's shouts" % (userprofile['full_name'] if has_fullname else userprofile['username'], ) page = define.common_page_start(self.user_id, title=page_title) page.append( define.render( template.user_shouts, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Myself profile.select_myself(self.user_id), # Comments shout.select(self.user_id, ownerid=otherid), # Feature "shouts", ])) return define.common_page_end(self.user_id, page, now=now)
def manage_collections_get_(request): form = request.web_input(feature="", backid="", nextid="") backid = int(form.backid) if form.backid else None nextid = int(form.nextid) if form.nextid else None config = define.get_config(request.userid) rating = define.get_rating(request.userid) if form.feature == "pending": return Response( define.webpage( request.userid, "manage/collections_pending.html", [ # Pending Collections collection.select_list(request.userid, rating, 30, otherid=request.userid, backid=backid, nextid=nextid, pending=True, config=config), request.userid ], title="Pending Collections")) return Response( define.webpage( request.userid, "manage/collections_accepted.html", [ # Accepted Collections collection.select_list(request.userid, rating, 30, otherid=request.userid, backid=backid, nextid=nextid, config=config), ], title="Accepted Collections"))
def GET(self): form = web.input(feature="", backid="", nextid="") backid = int(form.backid) if form.backid else None nextid = int(form.nextid) if form.nextid else None config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) if form.feature == "pending": return define.webpage(self.user_id, "manage/collections_pending.html", [ # Pending Collections collection.select_list(self.user_id, rating, 30, otherid=self.user_id, backid=backid, nextid=nextid, pending=True, config=config), self.user_id ]) return define.webpage(self.user_id, "manage/collections_accepted.html", [ # Accepted Collections collection.select_list(self.user_id, rating, 30, otherid=self.user_id, backid=backid, nextid=nextid, config=config), ])
def manage_collections_get_(request): form = request.web_input(feature="", backid="", nextid="") backid = int(form.backid) if form.backid else None nextid = int(form.nextid) if form.nextid else None config = define.get_config(request.userid) rating = define.get_rating(request.userid) if form.feature == "pending": return Response(define.webpage(request.userid, "manage/collections_pending.html", [ # Pending Collections collection.select_list(request.userid, rating, 30, otherid=request.userid, backid=backid, nextid=nextid, pending=True, config=config), request.userid ])) return Response(define.webpage(request.userid, "manage/collections_accepted.html", [ # Accepted Collections collection.select_list(request.userid, rating, 30, otherid=request.userid, backid=backid, nextid=nextid, config=config), ]))
def GET(self): config = define.get_config(self.user_id) current_rating, current_sfw_rating = define.get_config_rating( self.user_id) age = profile.get_user_age(self.user_id) allowed_ratings = ratings.get_ratings_for_age(age) jsonb_settings = define.get_profile_settings(self.user_id) return define.webpage( self.user_id, "control/edit_preferences.html", [ # Config config, jsonb_settings, # Rating current_rating, current_sfw_rating, age, allowed_ratings, web.ctx.weasyl_session.timezone.timezone, define.timezones(), ])
def GET(self): form = web.input(feature="", backid="", nextid="") backid = int(form.backid) if form.backid else None nextid = int(form.nextid) if form.nextid else None config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) if form.feature == "pending": return define.webpage( self.user_id, "manage/collections_pending.html", [ # Pending Collections collection.select_list(self.user_id, rating, 30, otherid=self.user_id, backid=backid, nextid=nextid, pending=True, config=config), self.user_id ]) return define.webpage( self.user_id, "manage/collections_accepted.html", [ # Accepted Collections collection.select_list(self.user_id, rating, 30, otherid=self.user_id, backid=backid, nextid=nextid, config=config), ])
def select_submit_query(userid, rating, otherid=None, backid=None, nextid=None, config=None): if config is None: config = d.get_config(userid) statement = [ " FROM favorite fa INNER JOIN" " submission su ON fa.targetid = su.submitid" " INNER JOIN profile pr ON su.userid = pr.userid" " WHERE fa.type = 's' AND su.settings !~ 'h'"] if userid: # filter own content in SFW mode if d.is_sfw_mode(): statement.append(" AND (su.rating <= %i)" % (rating,)) else: statement.append(" AND (su.userid = %i OR su.rating <= %i)" % (userid, rating)) statement.append(m.MACRO_IGNOREUSER % (userid, "su")) statement.append(m.MACRO_BLOCKTAG_SUBMIT % (userid, userid)) statement.append(m.MACRO_FRIENDUSER_SUBMIT % (userid, userid, userid)) else: statement.append(" AND su.rating <= %i" % (rating,)) statement.append(" AND su.settings !~ 'f'") if otherid: statement.append(" AND fa.userid = %i" % otherid) if backid: statement.append(" AND fa.unixtime > " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 's'))" % (otherid, backid)) elif nextid: statement.append(" AND fa.unixtime < " "(SELECT unixtime FROM favorite WHERE (userid, targetid, type) = (%i, %i, 's'))" % (otherid, nextid)) return statement
def associate(userid, tags, submitid=None, charid=None, journalid=None, preferred_tags_userid=None, optout_tags_userid=None): """ Associates searchtags with a content item. Parameters: userid: The userid of the user associating tags tags: A set of tags submitid: The ID number of a submission content item to associate ``tags`` to. (default: None) charid: The ID number of a character content item to associate ``tags`` to. (default: None) journalid: The ID number of a journal content item to associate ``tags`` to. (default: None) preferred_tags_userid: The ID number of a user to associate ``tags`` to for Preferred tags. (default: None) optout_tags_userid: The ID number of a user to associate ``tags`` to for Opt-Out tags. (default: None) Returns: A dict containing two elements. 1) ``add_failure_restricted_tags``, which contains a space separated string of tag titles which failed to be added to the content item due to the user or global restricted tag lists; and 2) ``remove_failure_owner_set_tags``, which contains a space separated string of tag titles which failed to be removed from the content item due to the owner of the aforementioned item prohibiting users from removing tags set by the content owner. If an element does not have tags, the element is set to None. If neither elements are set, the function returns None. """ targetid = d.get_targetid(submitid, charid, journalid) # Assign table, feature, ownerid if submitid: table, feature = "searchmapsubmit", "submit" ownerid = d.get_ownerid(submitid=targetid) elif charid: table, feature = "searchmapchar", "char" ownerid = d.get_ownerid(charid=targetid) elif journalid: table, feature = "searchmapjournal", "journal" ownerid = d.get_ownerid(journalid=targetid) elif preferred_tags_userid: table, feature = "artist_preferred_tags", "user" targetid = ownerid = preferred_tags_userid elif optout_tags_userid: table, feature = "artist_optout_tags", "user" targetid = ownerid = optout_tags_userid else: raise WeasylError("Unexpected") # Check permissions and invalid target if not ownerid: raise WeasylError("TargetRecordMissing") elif userid != ownerid and ("g" in d.get_config(userid) or preferred_tags_userid or optout_tags_userid): # disallow if user is forbidden from tagging, or trying to set artist tags on someone other than themselves raise WeasylError("InsufficientPermissions") elif ignoreuser.check(ownerid, userid): raise WeasylError("contentOwnerIgnoredYou") # Determine previous tagids, titles, and settings existing = d.engine.execute( "SELECT tagid, title, settings FROM {} INNER JOIN searchtag USING (tagid) WHERE targetid = %(target)s".format(table), target=targetid).fetchall() # Retrieve tag titles and tagid pairs, for new (if any) and existing tags query = add_and_get_searchtags(tags) existing_tagids = {t.tagid for t in existing} entered_tagids = {t.tagid for t in query} # Assign added and removed added = entered_tagids - existing_tagids removed = existing_tagids - entered_tagids # enforce the limit on artist preference tags if preferred_tags_userid and (len(added) - len(removed) + len(existing)) > MAX_PREFERRED_TAGS: raise WeasylError("tooManyPreferenceTags") # Track which tags fail to be added or removed to later notify the user (Note: These are tagids at this stage) add_failure_restricted_tags = None remove_failure_owner_set_tags = None # If the modifying user is not the owner of the object, and is not staff, check user/global restriction lists if userid != ownerid and userid not in staff.MODS: user_rtags = set(query_user_restricted_tags(ownerid)) global_rtags = set(query_global_restricted_tags()) add_failure_restricted_tags = remove_restricted_tags(user_rtags | global_rtags, query) added -= add_failure_restricted_tags if len(add_failure_restricted_tags) == 0: add_failure_restricted_tags = None # Check removed artist tags if not can_remove_tags(userid, ownerid): existing_artist_tags = {t.tagid for t in existing if 'a' in t.settings} remove_failure_owner_set_tags = removed & existing_artist_tags removed.difference_update(existing_artist_tags) entered_tagids.update(existing_artist_tags) # Submission items use a different method of tag protection for artist tags; ignore them if submitid or len(remove_failure_owner_set_tags) == 0: remove_failure_owner_set_tags = None # Remove tags if removed: d.engine.execute( "DELETE FROM {} WHERE targetid = %(target)s AND tagid = ANY (%(removed)s)".format(table), target=targetid, removed=list(removed)) if added: d.engine.execute( "INSERT INTO {} SELECT tag, %(target)s FROM UNNEST (%(added)s) AS tag".format(table), target=targetid, added=list(added)) # preference/optout tags can only be set by the artist, so this settings column does not apply if userid == ownerid and not (preferred_tags_userid or optout_tags_userid): d.execute( "UPDATE %s SET settings = settings || 'a' WHERE targetid = %i AND tagid IN %s", [table, targetid, d.sql_number_list(list(added))]) if submitid: d.engine.execute( 'INSERT INTO submission_tags (submitid, tags) VALUES (%(submission)s, %(tags)s) ' 'ON CONFLICT (submitid) DO UPDATE SET tags = %(tags)s', submission=submitid, tags=list(entered_tagids)) db = d.connect() db.execute( d.meta.tables['tag_updates'].insert() .values(submitid=submitid, userid=userid, added=tag_array(added), removed=tag_array(removed))) if userid != ownerid: welcome.tag_update_insert(ownerid, submitid) files.append( "%stag.%s.%s.log" % (m.MACRO_SYS_LOG_PATH, feature, d.get_timestamp()), "-%sID %i -T %i -UID %i -X %s\n" % (feature[0].upper(), targetid, d.get_time(), userid, " ".join(tags))) # Return dict with any tag titles as a string that failed to be added or removed if add_failure_restricted_tags or remove_failure_owner_set_tags: if add_failure_restricted_tags: add_failure_restricted_tags = " ".join({tag.title for tag in query if tag.tagid in add_failure_restricted_tags}) if remove_failure_owner_set_tags: remove_failure_owner_set_tags = " ".join({tag.title for tag in existing if tag.tagid in remove_failure_owner_set_tags}) return {"add_failure_restricted_tags": add_failure_restricted_tags, "remove_failure_owner_set_tags": remove_failure_owner_set_tags} else: return None
def favorites_(request): def _FEATURE(target): if target == "submit": return 10 elif target == "char": return 20 elif target == "journal": return 30 else: return 0 form = request.web_input(userid="", name="", feature="", backid=None, nextid=None) form.name = request.matchdict.get('name', form.name) form.userid = define.get_int(form.userid) config = define.get_config(request.userid) rating = define.get_rating(request.userid) otherid = profile.resolve(request.userid, form.userid, form.name) # TODO(hyena): Why aren't more of these WeasylErrors? if not otherid: raise WeasylError("userRecordMissing") elif not request.userid and "h" in define.get_config(otherid): return Response(define.errorpage(request.userid, errorcode.no_guest_access)) elif request.userid != otherid and 'v' in define.get_config(otherid): return Response(define.errorpage( request.userid, "You cannot view this page because the owner does not allow anyone to see their favorites.")) userprofile = profile.select_profile(otherid, images=True, viewer=request.userid) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's favorites" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(request.userid, title=page_title) if form.feature: nextid = define.get_int(form.nextid) backid = define.get_int(form.backid) url_format = ( "/favorites?userid={userid}&feature={feature}&%s".format(userid=userprofile['userid'], feature=form.feature)) id_field = form.feature + "id" count_function = None if form.feature == "submit": select_function = favorite.select_submit count_function = favorite.select_submit_count elif form.feature == "char": select_function = favorite.select_char elif form.feature == "journal": select_function = favorite.select_journal else: raise httpexceptions.HTTPNotFound() faves = pagination.PaginatedResult( select_function, count_function, id_field, url_format, request.userid, rating, 60, otherid=otherid, backid=backid, nextid=nextid, config=config) else: faves = { "submit": favorite.select_submit(request.userid, rating, 22, otherid=otherid, config=config), "char": favorite.select_char(request.userid, rating, 22, otherid=otherid, config=config), "journal": favorite.select_journal(request.userid, rating, 22, otherid=otherid, config=config), } page.append(define.render('user/favorites.html', [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(request.userid, otherid), # Feature form.feature, # Favorites faves, ])) return Response(define.common_page_end(request.userid, page))
def can_remove_tags(userid, ownerid): return userid == ownerid or userid in staff.MODS or 'k' not in d.get_config( ownerid)
def GET(self, name=""): now = time.time() form = web.input(userid="", name="") form.name = name if name else form.name form.userid = define.get_int(form.userid) config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) extras = { "canonical_url": "/~" + define.get_sysname(form.name) } if define.user_is_twitterbot(): extras['twitter_card'] = profile.twitter_card(otherid) extras['options'] = ['nocache'] if not self.user_id and "h" in userprofile['config']: return define.errorpage( self.user_id, "You cannot view this page because the owner does not allow guests to view their profile.", **extras) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' extras['title'] = u"%s's profile" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(self.user_id, **extras) define.common_view_content(self.user_id, otherid, "profile") if 'O' in userprofile['config']: submissions = collection.select_list( self.user_id, rating, 11, otherid=otherid, options=["cover"], config=config) more_submissions = 'collections' featured = None elif 'A' in userprofile['config']: submissions = character.select_list( self.user_id, rating, 11, otherid=otherid, options=["cover"], config=config) more_submissions = 'characters' featured = None else: submissions = submission.select_list( self.user_id, rating, 11, otherid=otherid, options=["cover"], config=config, profile_page_filter=True) more_submissions = 'submissions' featured = submission.select_featured(self.user_id, otherid, rating) if userprofile['show_favorites_bar']: favorites = favorite.select_submit(self.user_id, rating, 11, otherid=otherid, config=config) else: favorites = None page.append(define.render(template.user_profile, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), macro.SOCIAL_SITES, # Relationship profile.select_relation(self.user_id, otherid), # Myself profile.select_myself(self.user_id), # Recent submissions submissions, more_submissions, favorites, featured, # Folders preview folder.select_preview(self.user_id, otherid, rating, 3), # Latest journal journal.select_latest(self.user_id, rating, otherid=otherid, config=config), # Recent shouts shout.select(self.user_id, ownerid=otherid, limit=8), # Statistics information profile.select_statistics(otherid), # Commission information commishinfo.select_list(otherid), # Friends frienduser.select(self.user_id, otherid, 5, choose=None), # Following followuser.select_following(self.user_id, otherid, choose=5), # Followed followuser.select_followed(self.user_id, otherid, choose=5), ])) return define.common_page_end(self.user_id, page, now=now)
def GET(self, name=""): def _FEATURE(target): if target == "submit": return 10 elif target == "char": return 20 elif target == "journal": return 30 else: return 0 form = web.input(userid="", name="", feature="", backid=None, nextid=None) form.name = name if name else form.name form.userid = define.get_int(form.userid) config = define.get_config(self.user_id) rating = define.get_rating(self.user_id) otherid = profile.resolve(self.user_id, form.userid, form.name) if not otherid: raise WeasylError("userRecordMissing") elif not self.user_id and "h" in define.get_config(otherid): return define.errorpage(self.user_id, errorcode.no_guest_access) elif self.user_id != otherid and 'v' in define.get_config(otherid): return define.errorpage( self.user_id, "You cannot view this page because the owner does not allow anyone to see their favorites.") userprofile = profile.select_profile(otherid, images=True, viewer=self.user_id) has_fullname = userprofile['full_name'] is not None and userprofile['full_name'].strip() != '' page_title = u"%s's favorites" % (userprofile['full_name'] if has_fullname else userprofile['username'],) page = define.common_page_start(self.user_id, title=page_title) if form.feature: nextid = define.get_int(form.nextid) backid = define.get_int(form.backid) url_format = ( "/favorites?userid={userid}&feature={feature}&%s".format(userid=userprofile['userid'], feature=form.feature)) id_field = form.feature + "id" count_function = None if form.feature == "submit": select_function = favorite.select_submit count_function = favorite.select_submit_count elif form.feature == "char": select_function = favorite.select_char elif form.feature == "journal": select_function = favorite.select_journal faves = pagination.PaginatedResult( select_function, count_function, id_field, url_format, self.user_id, rating, 60, otherid=otherid, backid=backid, nextid=nextid, config=config) else: faves = { "submit": favorite.select_submit(self.user_id, rating, 22, otherid=otherid, config=config), "char": favorite.select_char(self.user_id, rating, 22, otherid=otherid, config=config), "journal": favorite.select_journal(self.user_id, rating, 22, otherid=otherid, config=config), } page.append(define.render(template.user_favorites, [ # Profile information userprofile, # User information profile.select_userinfo(otherid, config=userprofile['config']), # Relationship profile.select_relation(self.user_id, otherid), # Feature form.feature, # Favorites faves, ])) return define.common_page_end(self.user_id, page)
def GET(self, login): userid = self.user_id otherid = profile.resolve_by_login(login) user = profile.select_profile(otherid) rating = d.get_rating(userid) u_config = d.get_config(userid) o_config = user.pop('config') o_settings = user.pop('settings') if not otherid and "h" in o_config: return json.dumps({ "error": { "code": 200, "text": "Profile hidden from unlogged users." }}) user.pop('userid', None) user.pop('commish_slots', None) user['created_at'] = d.iso8601(user.pop('unixtime')) user['media'] = api.tidy_all_media(user.pop('user_media')) user['login_name'] = d.get_sysname(user['username']) user['profile_text'] = markdown(user['profile_text']) folders = folder.select_list(otherid, "api/all") if folders: old_folders = folders folders = list() for fldr in (i for i in old_folders if 'parentid' not in i): newfolder = { "folder_id": fldr['folderid'], "title": fldr['title'] } if fldr['haschildren']: subfolders = list() for sub in (i for i in old_folders if 'parentid' in i and i['parentid'] == fldr['folderid']): subfolders.append({ "folder_id": sub['folderid'], "title": sub['title'] }) newfolder['subfolders'] = subfolders folders.append(newfolder) user['folders'] = folders commissions = { "details": None, "price_classes": None, "commissions": self.convert_commission_setting(o_settings[0]), "trades": self.convert_commission_setting(o_settings[1]), "requests": self.convert_commission_setting(o_settings[2]) } commission_list = commishinfo.select_list(otherid) if commission_list: commissions['details'] = commission_list['content'] if len(commission_list['class']) > 0: classes = list() for cclass in commission_list['class']: commission_class = { "title": cclass['title'] } if len(commission_list['price']) > 0: prices = list() for cprice in (i for i in commission_list['price'] if i['classid'] == cclass['classid']): if 'a' in cprice['settings']: ptype = 'additional' else: ptype = 'base' price = { "title": cprice['title'], "price_min": self.convert_commission_price(cprice['amount_min'], cprice['settings']), "price_max": self.convert_commission_price(cprice['amount_min'], cprice['settings']), 'price_type': ptype } prices.append(price) commission_class['prices'] = prices classes.append(commission_class) commissions['price_classes'] = classes user['commission_info'] = commissions user['relationship'] = profile.select_relation(userid, otherid) if userid else None if 'O' in o_config: submissions = collection.select_list( userid, rating, 11, otherid=otherid, options=["cover"], config=u_config) more_submissions = 'collections' featured = None elif 'A' in o_config: submissions = character.select_list( userid, rating, 11, otherid=otherid, options=["cover"], config=u_config) more_submissions = 'characters' featured = None else: submissions = submission.select_list( userid, rating, 11, otherid=otherid, options=["cover"], config=u_config, profile_page_filter=True) more_submissions = 'submissions' featured = submission.select_featured(userid, otherid, rating) if submissions: submissions = map(tidy_submission, submissions) user['recent_submissions'] = submissions user['recent_type'] = more_submissions if featured: featured = tidy_submission(featured) user['featured_submission'] = featured statistics = profile.select_statistics(otherid) if statistics: statistics.pop('staff_notes') user['statistics'] = statistics user_info = profile.select_userinfo(otherid) if user_info: if not user_info['show_age']: user_info['age'] = None user_info.pop('show_age', None) user_info.pop('birthday', None) user_info['location'] = user_info.pop('country', None) user['user_info'] = user_info user['link'] = d.absolutify_url("/~" + user['login_name']) return json.dumps(user)
def can_remove_tags(userid, ownerid): return userid == ownerid or userid in staff.MODS or 'k' not in d.get_config(ownerid)
def associate(userid, tags, submitid=None, charid=None, journalid=None): targetid = d.get_targetid(submitid, charid, journalid) # Assign table, feature, ownerid if submitid: table, feature = "searchmapsubmit", "submit" ownerid = d.get_ownerid(submitid=targetid) elif charid: table, feature = "searchmapchar", "char" ownerid = d.get_ownerid(charid=targetid) else: table, feature = "searchmapjournal", "journal" ownerid = d.get_ownerid(journalid=targetid) # Check permissions and invalid target if not ownerid: raise WeasylError("TargetRecordMissing") elif userid != ownerid and "g" in d.get_config(userid): raise WeasylError("InsufficientPermissions") elif ignoreuser.check(ownerid, userid): raise WeasylError("contentOwnerIgnoredYou") # Determine previous tags existing = d.engine.execute( "SELECT tagid, settings FROM {} WHERE targetid = %(target)s".format(table), target=targetid).fetchall() # Determine tag titles and tagids query = d.engine.execute( "SELECT tagid, title FROM searchtag WHERE title = ANY (%(tags)s)", tags=list(tags)).fetchall() newtags = list(tags - {x.title for x in query}) if newtags: query.extend( d.engine.execute( "INSERT INTO searchtag (title) SELECT * FROM UNNEST (%(newtags)s) AS title RETURNING tagid, title", newtags=newtags ).fetchall()) existing_tagids = {t.tagid for t in existing} entered_tagids = {t.tagid for t in query} # Assign added and removed added = entered_tagids - existing_tagids removed = existing_tagids - entered_tagids # Check removed artist tags if not can_remove_tags(userid, ownerid): existing_artist_tags = {t.tagid for t in existing if 'a' in t.settings} removed.difference_update(existing_artist_tags) entered_tagids.update(existing_artist_tags) # Remove tags if removed: d.engine.execute( "DELETE FROM {} WHERE targetid = %(target)s AND tagid = ANY (%(removed)s)".format(table), target=targetid, removed=list(removed)) if added: d.engine.execute( "INSERT INTO {} SELECT tag, %(target)s FROM UNNEST (%(added)s) AS tag".format(table), target=targetid, added=list(added)) if userid == ownerid: d.execute( "UPDATE %s SET settings = settings || 'a' WHERE targetid = %i AND tagid IN %s", [table, targetid, d.sql_number_list(list(added))]) if submitid: d.engine.execute( 'INSERT INTO submission_tags (submitid, tags) VALUES (%(submission)s, %(tags)s) ' 'ON CONFLICT (submitid) DO UPDATE SET tags = %(tags)s', submission=submitid, tags=list(entered_tagids)) db = d.connect() db.execute( d.meta.tables['tag_updates'].insert() .values(submitid=submitid, userid=userid, added=tag_array(added), removed=tag_array(removed))) if userid != ownerid: welcome.tag_update_insert(ownerid, submitid) files.append( "%stag.%s.%s.log" % (m.MACRO_SYS_LOG_PATH, feature, d.get_timestamp()), "-%sID %i -T %i -UID %i -X %s\n" % (feature[0].upper(), targetid, d.get_time(), userid, " ".join(tags)))