def POST_unmute_participant(self, conversation): if conversation.is_internal or conversation.is_auto: return self.send_error(400, errors.CANT_RESTRICT_MODERATOR) sr = Subreddit._by_fullname(conversation.owner_fullname) try: participant = conversation.get_participant_account() except NotFound: abort(404, errors.USER_DOESNT_EXIST) if not c.user_is_admin: if not sr.is_moderator_with_perms(c.user, 'access', 'mail'): return self.send_error(403, errors.INVALID_MOD_PERMISSIONS) removed = sr.remove_muted(participant) if not removed: return simplejson.dumps( self._convo_to_serializable(conversation, all_messages=True)) MutedAccountsBySubreddit.unmute(sr, participant) ModAction.create(sr, c.user, 'unmuteuser', target=participant) conversation.add_action(c.user, 'unmuted', commit=True) result = self._get_updated_convo(conversation.id, c.user) result['user'] = self._get_modmail_userinfo(conversation, sr=sr) return simplejson.dumps(result)
def POST_unarchive(self, conversation): self._validate_vmodconversation() sr = Subreddit._by_fullname(conversation.owner_fullname) self._feature_enabled_check(sr) if sr.is_moderator_with_perms(c.user, 'mail'): if conversation.state != ModmailConversation.STATE['archived']: response.status_code = 204 return if conversation.is_internal: return self.send_error( 422, errors.CONVERSATION_NOT_ARCHIVABLE, ) conversation.add_action(c.user, 'unarchived') conversation.set_state('inprogress') updated_convo = self._get_updated_convo(conversation.id, c.user) g.events.new_modmail_event( 'ss.modmail_mark_thread', conversation, mark_type='unarchive', request=request, context=c, ) return simplejson.dumps(updated_convo) else: return self.send_error(403, errors.INVALID_MOD_PERMISSIONS)
def set_downs(): sr_counts = count.get_sr_counts() names = [k for k, v in sr_counts.iteritems() if v != 0] srs = Subreddit._by_fullname(names) for name in names: sr, c = srs[name], sr_counts[name] if c != sr._downs and c > 0: sr._downs = max(c, 0) sr._commit()
def set_downs(): sr_counts = count.get_sr_counts() names = [k for k, v in sr_counts.iteritems() if v != 0] srs = Subreddit._by_fullname(names) for name in names: sr,c = srs[name], sr_counts[name] if c != sr._downs and c > 0: sr._downs = max(c, 0) sr._commit()
def POST_mute_participant(self, conversation): if conversation.is_internal or conversation.is_auto: return self.send_error(400, errors.CANT_RESTRICT_MODERATOR) sr = Subreddit._by_fullname(conversation.owner_fullname) try: participant = conversation.get_participant_account() except NotFound: return self.send_error(404, errors.USER_DOESNT_EXIST) if not sr.can_mute(c.user, participant): return self.send_error(400, errors.CANT_RESTRICT_MODERATOR) if not c.user_is_admin: if not sr.is_moderator_with_perms(c.user, 'access', 'mail'): return self.send_error(403, errors.INVALID_MOD_PERMISSIONS) if sr.use_quotas: sr_ratelimit = SimpleRateLimit( name="sr_muted_%s" % sr._id36, seconds=g.sr_quota_time, limit=g.sr_muted_quota, ) if not sr_ratelimit.record_and_check(): return self.send_error(403, errors.SUBREDDIT_RATELIMIT) # Add the mute record but only if successful create the # appropriate notifications, this prevents duplicate # notifications from being sent added = sr.add_muted(participant) if not added: return simplejson.dumps( self._convo_to_serializable(conversation, all_messages=True)) MutedAccountsBySubreddit.mute(sr, participant, c.user) permalink = conversation.make_permalink() # Create the appropriate objects to be displayed on the # mute moderation log, use the permalink to the new modmail # system ModAction.create(sr, c.user, 'muteuser', target=participant, description=permalink) sr.add_rel_note('muted', participant, permalink) # Add the muted mod action to the conversation conversation.add_action(c.user, 'muted', commit=True) result = self._get_updated_convo(conversation.id, c.user) result['user'] = self._get_modmail_userinfo(conversation, sr=sr) return simplejson.dumps(result)
def _try_get_subreddit_access(self, conversation, admin_override=False): sr = Subreddit._by_fullname(conversation.owner_fullname) self._feature_enabled_check(sr) if (not sr.is_moderator_with_perms(c.user, 'mail') and not (admin_override and c.user_is_admin)): return self.send_error( 403, errors.SUBREDDIT_NO_ACCESS, ) return sr
def _get_modmail_userinfo(self, conversation, sr=None): if conversation.is_internal: raise ValueError('Cannot get userinfo for internal conversations') if not sr: sr = Subreddit._by_fullname(conversation.owner_fullname) # Retrieve the participant associated with the conversation try: account = conversation.get_participant_account() if not account: raise ValueError('No account associated with convo') permatimeout = (account.in_timeout and account.days_remaining_in_timeout == 0) if account._deleted or permatimeout: raise ValueError('User info is inaccessible') except NotFound: raise NotFound('Unable to retrieve conversation participant') # Fetch the mute and ban status of the participant as it relates # to the subreddit associated with the conversation. mute_status = sr.is_muted(account) ban_status = sr.is_banned(account) # Parse the ban status and retrieve the length of the ban, # then output the data into a serialiazable dict ban_result = { 'isBanned': bool(ban_status), 'reason': '', 'endDate': None, 'isPermanent': False } if ban_status: ban_result['reason'] = getattr(ban_status, 'note', '') ban_duration = sr.get_tempbans('banned', account.name) ban_duration = ban_duration.get(account.name) if ban_duration: ban_result['endDate'] = ban_duration.isoformat() else: ban_result['isPermanent'] = True ban_result['endDate'] = None # Parse the mute status and retrieve the length of the ban, # then output the data into the serialiazable dict mute_result = { 'isMuted': bool(mute_status), 'endDate': None, 'reason': '' } if mute_status: mute_result['reason'] = getattr(mute_status, 'note', '') muted_items = sr.get_muted_items(account.name) mute_duration = muted_items.get(account.name) if mute_duration: mute_result['endDate'] = mute_duration.isoformat() # Retrieve the participants post and comment fullnames from cache post_fullnames = [] comment_fullnames = [] if not account._spam: post_fullnames = list(queries.get_submitted(account, 'new', 'all'))[:100] comment_fullnames = list( queries.get_comments(account, 'new', 'all'))[:100] # Retrieve the associated link objects for posts and comments # using the retrieve fullnames, afer the link objects are retrieved # create a serializable dict with the the necessary information from # the endpoint. lookup_fullnames = list(set(post_fullnames) | set(comment_fullnames)) posts = Thing._by_fullname(lookup_fullnames) serializable_posts = {} for fullname in post_fullnames: if len(serializable_posts) == 3: break post = posts[fullname] if post.sr_id == sr._id and not post._deleted: serializable_posts[fullname] = { 'title': post.title, 'permalink': post.make_permalink(sr, force_domain=True), 'date': post._date.isoformat(), } # Extract the users most recent comments associated with the # subreddit sr_comments = [] for fullname in comment_fullnames: if len(sr_comments) == 3: break comment = posts[fullname] if comment.sr_id == sr._id and not comment._deleted: sr_comments.append(comment) # Retrieve all associated link objects (combines lookup) comment_links = Link._byID( [sr_comment.link_id for sr_comment in sr_comments]) # Serialize all of the user's sr comments serializable_comments = {} for sr_comment in sr_comments: comment_link = comment_links[sr_comment.link_id] comment_body = sr_comment.body if len(comment_body) > 140: comment_body = '{:.140}...'.format(comment_body) serializable_comments[sr_comment._fullname] = { 'title': comment_link.title, 'comment': comment_body, 'permalink': sr_comment.make_permalink(comment_link, sr, force_domain=True), 'date': sr_comment._date.isoformat(), } return { 'id': account._fullname, 'name': account.name, 'created': account._date.isoformat(), 'banStatus': ban_result, 'isShadowBanned': account._spam, 'muteStatus': mute_result, 'recentComments': serializable_comments, 'recentPosts': serializable_posts, }
def POST_mod_messages(self, conversation, msg_body, is_author_hidden, is_internal): """Creates a new message for a particular ModmailConversation URL Params: conversation_id -- id of the conversation to post a new message to POST Params: body -- this is the message body isAuthorHidden -- boolean on whether to hide author, i.e. respond as the subreddit isInternal -- boolean to signify a moderator only message """ self._validate_vmodconversation() sr = Subreddit._by_fullname(conversation.owner_fullname) self._feature_enabled_check(sr) # make sure the user is not muted before posting a message if sr.is_muted(c.user): return self.send_error(400, errors.USER_MUTED) if conversation.is_internal and not is_internal: is_internal = True is_mod = sr.is_moderator(c.user) if not is_mod and is_author_hidden: return self.send_error( 403, errors.MOD_REQUIRED, fields='isAuthorHidden', ) elif not is_mod and is_internal: return self.send_error( 403, errors.MOD_REQUIRED, fields='isInternal', ) try: if not conversation.is_internal and not conversation.is_auto: participant = conversation.get_participant_account() if participant and sr.is_muted(participant): return self.send_error( 400, errors.MUTED_FROM_SUBREDDIT, ) except NotFound: pass try: new_message = conversation.add_message( c.user, msg_body, is_author_hidden=is_author_hidden, is_internal=is_internal, ) except: return self.send_error(500, errors.MODMAIL_MESSAGE_NOT_SAVED) # Add the message to the legacy messaging system as well (unless it's # an internal message on a non-internal conversation, since we have no # way to hide specific messages from the external participant) legacy_incompatible = is_internal and not conversation.is_internal if (conversation.legacy_first_message_id and not legacy_incompatible): first_message = Message._byID(conversation.legacy_first_message_id) subject = conversation.subject if not subject.startswith('re: '): subject = 're: ' + subject # Retrieve the participant to decide whether to send the message # to the sr or to the participant. If the currently logged in user # is the same as the participant then address the message to the # sr. recipient = sr if not is_internal: try: participant = ( ModmailConversationParticipant.get_participant( conversation.id)) is_participant = ( (c.user._id == participant.account_id) and not sr.is_moderator_with_perms(c.user, 'mail')) if not is_participant: recipient = Account._byID(participant.account_id) except NotFound: pass message, inbox_rel = Message._new( c.user, recipient, subject, msg_body, request.ip, parent=first_message, from_sr=is_author_hidden, create_modmail=False, ) queries.new_message(message, inbox_rel) serializable_convo = conversation.to_serializable( entity=sr, all_messages=True, current_user=c.user, ) messages = serializable_convo.pop('messages') g.events.new_modmail_event( 'ss.send_modmail_message', conversation, message=new_message, msg_author=c.user, sr=sr, request=request, context=c, ) response.status_code = 201 return simplejson.dumps({ 'conversation': serializable_convo, 'messages': messages, })