def staff_api_console(request): """ Shows an html wrapper around our APIs that staff can use. """ from canvas.js_api import get_api_calls import drawquest.apps.stars.api import drawquest.apps.stars.api import drawquest.apps.drawquest_auth.api import drawquest.apps.iap.api import drawquest.apps.quests.api import drawquest.apps.quest_comments.api import drawquest.apps.playback.api import drawquest.apps.palettes.api import drawquest.apps.push_notifications.api import drawquest.apps.following.api import drawquest.apps.timeline.api import drawquest.apps.tumblr.api from drawquest.api_decorators import api_functions api_dict = defaultdict(lambda: []) # Group apis by their prefix. api_key = lambda func: func.url.strip("/").split("/")[1] functions = get_api_calls(api_functions=api_functions, ignore_unfound=True) for key, api_calls in itertools.groupby(functions, api_key): api_dict[key].extend(api_calls) apis = [] for key, api_calls in api_dict.items(): apis.append(dict(name=key, commands=api_calls)) # Order apis alphabetically apis = sorted(apis, key=lambda entry: entry.get("name")) # Inspect it. # @todo: Add a "staff" api for staff only calls. #apis = [dict(path="/api/", name="Canvas API", commands=functions)] # @gotcha: Be sure to use r2r, else {% csrf_token %} won't work. return r2r("api_wrapper.django.html", dict(apis=apis, request=request))
def debug_fact_stream(request): return r2r('debug_fact_stream.django.html', { 'request': request, 'funnels': dict((name, [step.name for step in funnel.steps],) for name,funnel in Funnels.by_name.iteritems()), 'debug_fact_channel': fact.debug_fact_channel().sync(), })
def facebook_iframe(request): fb_message_id = request.GET.get('request_ids') try: fb_user, fb = get_fb_api(request) app_requests = fb.request('{}/apprequests'.format(fb_user['id'])) redirect_url = None for app_request in app_requests['data']: if not redirect_url: redirect_url = app_request.get('data') fb.delete_object(app_request['id']) if not redirect_url: redirect_url = '/' except NotLoggedIntoFacebookError: redirect_url = '/' context = { 'request': request, 'fb_message_id': fb_message_id, 'redirect_url': redirect_url, } resp = r2r('facebook_app/facebook_iframe.django.html', context) resp.set_cookie('fb_message_id', fb_message_id) return resp
def staff_api_console(request): """ Shows an html wrapper around our APIs that staff can use. """ from canvas.js_api import get_api_calls import drawquest.apps.stars.api import drawquest.apps.stars.api import drawquest.apps.drawquest_auth.api import drawquest.apps.iap.api import drawquest.apps.quests.api import drawquest.apps.quest_comments.api import drawquest.apps.playback.api import drawquest.apps.palettes.api import drawquest.apps.push_notifications.api import drawquest.apps.following.api import drawquest.apps.timeline.api import drawquest.apps.tumblr.api from drawquest.api_decorators import api_functions api_dict = defaultdict(lambda: []) # Group apis by their prefix. api_key = lambda func: func.url.strip("/").split("/")[1] functions = get_api_calls(api_functions=api_functions, ignore_unfound=True) for key, api_calls in itertools.groupby(functions, api_key): api_dict[key].extend(api_calls) apis = [] for key, api_calls in api_dict.items(): apis.append(dict(name=key, commands=api_calls)) # Order apis alphabetically apis = sorted(apis, key=lambda entry: entry.get("name")) # Inspect it. # @todo: Add a "staff" api for staff only calls. # apis = [dict(path="/api/", name="Canvas API", commands=functions)] # @gotcha: Be sure to use r2r, else {% csrf_token %} won't work. return r2r("api_wrapper.django.html", dict(apis=apis, request=request))
def signup(request, skip_invite_code=None, template="signup/signup.html", success_redirect="/onboarding/start"): cookies_to_delete = [] cookies_to_set = {} error_context = get_signup_context(request, skip_invite_code, template, cookies_to_set, cookies_to_delete) Metrics.signup_form_view.record(request) def process_response(response): for key in cookies_to_delete: response.delete_cookie(key) for key, val in cookies_to_set.items(): response.set_cookie(key, val) return response if not error_context: # error_context is only None if this is a POST (and with no errors). # DEPRECATED: next and next_params. we use cookies for these now - see get_signup_context if request.POST.get('next'): next_params = request.POST.get('next_params', '') if next_params: next_params = '?' + next_params success_redirect = request.POST['next'] return process_response(HttpResponseRedirect(success_redirect + next_params)) return process_response(HttpResponseRedirect(success_redirect)) else: request.session['failed_signup'] = True if template == "signup_prompt.django.html": return process_response(r2r(template, error_context)) return process_response(r2r_jinja(template, error_context, request))
def group_about(request, name): category = get_object_or_404(Category, name=name) category_disabled = category.visibility == Visibility.DISABLED founder = category.founder moderators = list(category.moderators.values_list('username', flat=True)) can_modify_group = category.can_modify(request.user) can_disable_group = category.can_disable(request.user) has_form = can_modify_group or can_disable_group return r2r('group/about.django.html', locals())
def thread(request, short_id, page=None, gotoreply=None, sort_by_top=False, template_name='comment/new_base_thread.django.html'): from apps.monster.models import MONSTER_GROUP if not request.user.is_authenticated() and template_name == 'comment/new_base_thread.django.html' and not features.thread_new(request): return logged_out_thread_view(request, short_id, page=page, gotoreply=gotoreply) view_data = CommentViewData(request, short_id, page=page, gotoreply=gotoreply) if '/p/' + short_id == request.user.kv.post_pending_signup_url.get(): request.user.kv.post_pending_signup_url.delete() ctx = view_data.thread_context() ctx['request'] = request # monstermash posts redirect to monstermash app if ctx['op_comment'].category == MONSTER_GROUP and not ctx['viewer_is_staff']: return HttpResponseRedirect('/monster/{0}'.format(ctx['op_comment'].short_id())) # all hidden group posts are invisible to normal users if ctx['op_comment'].category in settings.HIDDEN_GROUPS and not ctx['viewer_is_staff']: return Http404() # If we hit the size threshold, record metric that the user is viewing a large thread if ctx['large_thread_view']: Metrics.large_thread_view.record(request) ctx['remix_invite_share_view'] = 'rmi' in request.GET if ctx['remix_invite_share_view']: ctx['fb_metadata']['title'] = "Come Remix With Me!" if ctx['op_comment'].title: ctx['fb_metadata']['description'] = """I just started a thread on Canvas, "{0}". Click the link to add your remix to the thread!""".format(op_comment.title) else: ctx['fb_metadata']['description'] = "I just started a thread on Canvas. Click the link to add your remix to the thread!" # Inviting experiment ctx['is_in_invite_remixers_v2'] = False ctx.update({ 'request': request, 'sort_by_top': sort_by_top, }) if request.is_mobile: return r2r_jinja("mobile/thread.html", ctx) if features.thread_new(request): ctx['has_top_remixes'] = bool(len(ctx['top_remixes'])) if sort_by_top: ctx['replies'] = ctx['top_remixes'] ctx['has_top_remixes'] = True return r2r_jinja('threads_new/thread.html', ctx, request) return r2r(template_name, ctx)
def staff_pulse(request): g = Grapher(request) M = lambda metric, fun_name='daily_uniques': lambda d: getattr(metric, fun_name)(d) graphs = [ g.gen_trailing('Daily Signups', M(Metrics.signup, 'daily_count')), g.gen_trailing('DAU (Daily Unique Viewers)', M(Metrics.view)), g.gen_trailing('Daily Unique Stickerers', M(Metrics.sticker)), g.gen_trailing('Daily Unique Posters', M(Metrics.post)), ] return r2r('staff/graphs.django.html', locals())
def staff_vanity_metrics(request): ytd = bool(request.GET.get('ytd')) enum_days = days if not ytd else days_ytd posts = Comment.all_objects.count() # Use the last id instead of count() so we can use this more reliably for email sending ranges. users = User.objects.order_by('-id')[0].id stickers = CommentSticker.objects.count() graphs = [] for cat_name, arg_lists in Metrics.names: counts, uniques, unique_ips = [], [], [] hourly_counts, hourly_uniques, hourly_unique_ips = [], [], [] for args in arg_lists: name = args[0] metric = getattr(Metrics, name) counts.append({ 'name': name, 'data': [metric.daily_count(d) for d in enum_days()], }) uniques.append({ 'name': name, 'data': [metric.daily_uniques(d) for d in enum_days()], }) unique_ips.append({ 'name': name, 'data': [metric.daily_uniques(d, True) for d in enum_days()], }) if not ytd: hourly_counts.append({ 'name': name, 'data': [metric.hourly_count(h) for h in hours()], }) hourly_uniques.append({ 'name': name, 'data': [metric.hourly_uniques(h) for h in hours()], }) hourly_unique_ips.append({ 'name': name, 'data': [metric.hourly_uniques(d, True) for d in hours()], }) graphs.append({'name': cat_name + ' counts', 'data': counts, 'primary': True, 'primary_name': cat_name}) graphs.append({'name': cat_name + ' uniques', 'data': uniques, 'primary': False}) graphs.append({'name': cat_name + ' unique ips', 'data': unique_ips, 'primary': False}) if not ytd: graphs.append({'name': cat_name + ' hourly counts', 'data': hourly_counts, 'primary': False}) graphs.append({'name': cat_name + ' hourly uniques', 'data': hourly_uniques, 'primary': False}) graphs.append({'name': cat_name + ' hourly unique ips', 'data': hourly_unique_ips, 'primary': False}) return r2r('staff/vanity_metrics.django.html', locals())
def warning(request): if request.method == "POST": for name in request.POST.keys(): match = re.match('confirm_(\d+)', name) if match: warning_id, = match.groups() warning = UserWarning.objects.get(user=request.user, id=warning_id) warning.confirm() warnings = list(UserWarning.objects.filter(user=request.user, confirmed=0)) if warnings: return r2r('warning.django.html', locals()) else: return HttpResponseRedirect('/warning/code_of_conduct')
def staff_api_console(request): """ Shows an html wrapper around our APIs that staff can use. """ from canvas.js_api import get_api_calls api_dict = defaultdict(lambda: []) # Group apis by their prefix. api_key = lambda func: func.url.strip("/").split("/")[1] functions = get_api_calls() for key, api_calls in itertools.groupby(functions, api_key): api_dict[key].extend(api_calls) apis = [] for key, api_calls in api_dict.items(): apis.append(dict(name=key, commands=api_calls)) # Order apis alphabetically apis = sorted(apis, key=lambda entry: entry.get("name")) # Inspect it. # @todo: Add a "staff" api for staff only calls. #apis = [dict(path="/api/", name="Canvas API", commands=functions)] return r2r("api_wrapper.django.html", dict(apis=apis, request=request))
def staff_user_view(request, username, key="user"): user = get_object_or_404(User, username=username) kwargs = {key: user} related = ['user', 'moderator'] comment_log = CommentModerationLog.objects.filter(**kwargs).order_by('-id').select_related(*(related+['comment', 'comment__parent_comment']))[:100] user_log = UserModerationLog.objects.filter(**kwargs).select_related(*related) time_dilation = user.kv.time_dilation.get() time_dilation_start = user.kv.time_dilation_start.get() time_dilation_end = user.kv.time_dilation_end.get() if time_dilation_start and time_dilation_end: time_dilation_days = int((time_dilation_end - time_dilation_start) / 86400) else: time_dilation_days = 0 sorted_logs = sorted(list(comment_log) + list(user_log), key=lambda log: -log.timestamp) # Warm the in-process-cache for the template uses of reply_content.details. CachedCall.multicall([log.comment.reply_content.details for log in comment_log if log.comment.reply_content]) logs = [(log, render_to_string('staff/modlog/' + log.log_template, {'log': log})) for log in sorted_logs] return r2r('staff/user_view.django.html', locals())
def staff_action(request): stickerers, posters, viewers = [], [], [] def safediv(num, div): return float(num) / div if div != 0 else 0 def intersect(metric, today): yesterday = today - datetime.timedelta(1) yesterday_signups = Metrics.signup.uniques(yesterday) today_metric = metric.uniques(today) returning_metric = RedisSet(gen_temp_key()) redis.sinterstore(returning_metric.key, [yesterday_signups.key, today_metric.key]) return safediv(returning_metric.scard(), yesterday_signups.scard()) g = Grapher(request) M = lambda metric: lambda d: intersect(metric, d) * 100 graphs = [ g.gen_trailing('2nd day viewer %', M(Metrics.view)), g.gen_trailing('2nd day stickerers %', M(Metrics.sticker)), g.gen_trailing('2nd day posters %', M(Metrics.post)), ] return r2r('staff/graphs.django.html', locals())
def signup(request, skip_invite_code=None, template="signup/signup.html", success_redirect="/onboarding/start"): cookies_to_delete = [] cookies_to_set = {} error_context = get_signup_context(request, skip_invite_code, template, cookies_to_set, cookies_to_delete) Metrics.signup_form_view.record(request) def process_response(response): for key in cookies_to_delete: response.delete_cookie(key) for key, val in cookies_to_set.items(): response.set_cookie(key, val) return response if not error_context: # error_context is only None if this is a POST (and with no errors). # DEPRECATED: next and next_params. we use cookies for these now - see get_signup_context if request.POST.get('next'): next_params = request.POST.get('next_params', '') if next_params: next_params = '?' + next_params success_redirect = request.POST['next'] return process_response( HttpResponseRedirect(success_redirect + next_params)) return process_response(HttpResponseRedirect(success_redirect)) else: request.session['failed_signup'] = True if template == "signup_prompt.django.html": return process_response(r2r(template, error_context)) return process_response(r2r_jinja(template, error_context, request))
def staff_ip_user_history(request, ip): ip_int = ip_to_int(ip) history = IP(ip_int).user_history.with_scores[:] users = User.objects.in_bulk_list([user for (user, ts) in history]) history = zip(users, [ts for (user, ts) in history]) return r2r('staff/user_history.django.html', locals())
def staff_user_ip_history(request, username): user = get_object_or_404(User, username=username) ip_history = [(int_to_ip(ip), timestamp) for (ip, timestamp) in user.redis.ip_history.with_scores[:]] return r2r('staff/ip_history.django.html', locals())
def draw(request): # Get the content_id of what we are remixing, or our blank white PNG if nothing. cid = request.GET.get('cid', Content.DRAW_FROM_SCRATCH_PK) remixing = get_object_or_404(Content.all_objects, id=cid).details() return r2r('draw.django.html', locals())
def staff_api_console(request): """ Shows an html wrapper around our APIs that staff can use. """ apis = _apis() return r2r("api_wrapper.django.html", dict(apis=apis, request=request))
def group_new(request): ctx = { 'found_limit_reached': request.user.found_limit_reached(), 'request': request, } return r2r('group/new.django.html', ctx)
def signup_share_prompt(request): post_pending_signup_url = request.user.kv.post_pending_signup_url.get() return r2r('share_prompt.django.html', locals())
def numbers(request): now = time.time() trailing_7day = now - 7 * 24 * 60 * 60 fmt = lambda n, tot: "%0.0f (%0.2f%%)" % (n, float(n)/tot*100) if tot else None all_users = User.objects.all() all_images = Content.all_objects.count() all_remixes = Content.all_objects.exclude(remix_of=None).count() l7d_images = Content.all_objects.filter(timestamp__gt=trailing_7day).count() l7d_remixes = Content.all_objects.exclude(remix_of=None).filter(timestamp__gt=trailing_7day).count() max_user_id = User.objects.order_by('-id')[0].id trailing_1000_users = User.objects.filter(id__gte=max_user_id-1000) women = lambda u: u.filter(facebookuser__gender=Gender.FEMALE).count() viral = lambda u: (u.aggregate(c=Count('sent_invites__invitee')).get('c', 0) + u.aggregate(c=Count('facebook_sent_invites__invitee')).get('c', 0)) sections = [ ( 'All time', [('Images', all_images), ('Remixes', fmt(all_remixes, all_images))] ), ( 'Last 7 days', [('Images', l7d_images), ('Remixes', fmt(l7d_remixes, l7d_images))] ), ( 'Trailing 1000 users', [('Women', women(trailing_1000_users)), ('Invited users (virality)', viral(trailing_1000_users))] ), ( 'All Users', [('Women', women(all_users)), ('Invited users (virality)', viral(all_users))] ), ] trailing_7day_dau = [Metrics.view.daily_uniques(d) for d in days(7)] users = User.objects.count() daily = sum(trailing_7day_dau) / 7.0 weekly = redis.scard(Metrics.view.trailing_uniques(7, gen_temp_key())) monthly = redis.scard(Metrics.view.trailing_uniques(30, gen_temp_key())) sections += [ ( 'Uniques (by view)', [ ('all users', users), ('daily (trailing 7day average)', fmt(daily, users)), ('weekly (trailing 7day cumulative)', fmt(weekly, users)), ('monthly (trailing 30day cumulative)', fmt(monthly, users)), ], ), ] #u = lambda table, cutoff: fmt(User.objects.annotate(count=Count(table)).filter(count__gt=cutoff).count(), users) # #sections += [ # ( 'Uniques (actions)', # [ # ('all users', users), # ('stickered', u('commentsticker', 0)), # ('stickered 25 times', u('commentsticker', 24)), # ('posted', u('comment', 0)), # ('posted 25 times', u('comment', 24)), # ('remixed', u('comment__reply_content__remix_of', 0)), # ('remixed 25 times', u('comment__reply_content__remix_of', 24)), # ], # ), #] return r2r('staff/numbers.django.html', locals())
def sticker_values(request): sorted_stickers = sorted([(stick.sort_key(1), stick) for stick in stickers.all_stickers()], reverse=True) return r2r('staff/sticker_values.django.html', locals())
def staff_vintage(request): vintage_today = calculate_vintage(datetime.date.today()) vintage_yesterday = calculate_vintage(datetime.date.today() - datetime.timedelta(1)) daily_cohorts = calculate_cohort(datetime.date.today(), 7, 7) weekly_cohorts = calculate_cohort(datetime.date.today(), 8, 8, rollup=7) return r2r('staff/vintage.django.html', locals())
def staff_user_browse(request): if request.method == "POST": email = request.POST['email'] matched_user = User.objects.get_or_none(email=email) recent_disablings = User.objects.filter(is_active=False, user_warnings__disable_user=True).annotate(issued=Max('user_warnings__issued')).order_by('-issued') return r2r('staff/user_browse.django.html', locals())
def unsubscribe(request): token = request.REQUEST.get('token', '') email = request.REQUEST.get('email') user_id = request.REQUEST.get('user_id') token_user = User.objects.get_or_none(id=user_id) if user_id else None unsubscribed = False unsubscribed_on_get = False if user_id and util.token(user_id) == token and token_user: user = token_user elif email and util.token(email) == token: # No user_id associated with the sent email, unsubscribe this email address from all email find_user = User.objects.filter(email=email) # If there is one and only one user with that email address, then pick them, otherwise we'll fall back to just an email address user = find_user[0] if find_user.count() == 1 else None elif request.user.is_authenticated(): # Token mismatch, but we have a logged in user. user = request.user else: error = True return r2r('unsubscribe.django.html', locals()) all_actions = EmailChannel.all_handled_actions() if user: subscriptions = user.kv.subscriptions # We need to handle any posts that are passed in the URL comment_id = request.GET.get('post') if comment_id: try: unsubscribed_post = Comment.objects.get(pk=int(comment_id)) except ObjectDoesNotExist: pass else: user.redis.mute_thread(unsubscribed_post) unsubscribed_from_thread = unsubscribed_on_get = unsubscribed = True Metrics.mute_thread.record(request) # Support for unsubscribe headers. # We support passing in 'actions' action = request.REQUEST.get('action') if action and action in EmailChannel.all_handled_actions(): unsubscribed_on_get = unsubscribed = True user.kv.subscriptions.unsubscribe(action) Metrics.unsubscribe_action.record(request, action=action, method=request.method) if request.method == 'POST': # Handle the 'ALL' case separately because the semantics for it are inverted. # ie, if ALL is checked, it means to DISABLE. While if REMIXED is checked, it means ENABLE. handle_unsubscribe_post(user, request.REQUEST, request) # We use this dictionary to render the checkboxes in the html. unsubscribed = unsubscribed or get_unsubscriptions(user, all_actions) unsubscribed_settings = get_unsubscriptions(user) else: unsubscribe_newsletter(email) unsubscribed = True Metrics.unsubscribe_email_address.record(request) return r2r('unsubscribe.django.html', locals())
def direct_to_django_template(request, template, **kwargs): return r2r('%s' % template, dict(kwargs, request=request))
def processlist(request): from django.db import connection cursor = connection.cursor() cursor.execute("SHOW FULL PROCESSLIST") processlist = cursor.fetchall() return r2r('staff/processlist.django.html', locals())
def epic_sticker_messages(request): stickers = CommentSticker.objects.exclude(epic_message='').order_by('-id') total = len(stickers) return r2r('staff/epic_sticker_messages.django.html', locals())