Example #1
0
def _thread_list(request, mlist, threads, template_name='hyperkitty/thread_list.html', extra_context=None):
    threads = paginate(threads, request.GET.get('page'),
                       results_per_page=request.GET.get('count'))
    for thread in threads:
        # Favorites
        thread.favorite = False
        if request.user.is_authenticated():
            try:
                Favorite.objects.get(thread=thread, user=request.user)
            except Favorite.DoesNotExist:
                pass
            else:
                thread.favorite = True
        # Category
        thread.category_hk, thread.category_form = \
            get_category_widget(request, thread.category)

    context = {
        'mlist' : mlist,
        'threads': threads,
        'months_list': get_months(mlist),
    }
    if extra_context is not None:
        context.update(extra_context)
    return render(request, template_name, context)
def _thread_list(request,
                 mlist,
                 threads,
                 template_name='hyperkitty/thread_list.html',
                 extra_context=None):
    threads = paginate(threads, request.GET.get('page'),
                       request.GET.get('count'))
    for thread in threads:
        # Favorites
        thread.favorite = False
        if request.user.is_authenticated:
            try:
                Favorite.objects.get(thread=thread, user=request.user)
            except Favorite.DoesNotExist:
                pass
            else:
                thread.favorite = True
        # Category
        thread.category_hk, thread.category_form = \
            get_category_widget(request, thread.category)

    context = {
        'mlist': mlist,
        'threads': threads,
        'months_list': get_months(mlist),
    }
    if extra_context is not None:
        context.update(extra_context)
    return render(request, template_name, context)
Example #3
0
def _thread_list(request, mlist, threads, template_name='hyperkitty/thread_list.html', extra_context=None):
    categories = [ (c.name, c.name.upper())
                   for c in ThreadCategory.objects.all() ] \
                 + [("", "no category")]
    threads = paginate(threads, request.GET.get('page'))
    for thread in threads:
        # Favorites
        thread.favorite = False
        if request.user.is_authenticated():
            try:
                Favorite.objects.get(thread=thread, user=request.user)
            except Favorite.DoesNotExist:
                pass
            else:
                thread.favorite = True
        # Category
        thread.category_hk, thread.category_form = \
            get_category_widget(request, thread.category, categories)

    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = { "type": FLASH_MESSAGES[flash_msg][0],
                      "msg": FLASH_MESSAGES[flash_msg][1] }
        flash_messages.append(flash_msg)

    context = {
        'mlist' : mlist,
        'threads': threads,
        'months_list': get_months(mlist),
        'flash_messages': flash_messages,
    }
    if extra_context is not None:
        context.update(extra_context)
    return render(request, template_name, context)
Example #4
0
def reattach(request, mlist_fqdn, threadid):
    if not request.user.is_staff:
        return HttpResponse('You must be a staff member to reattach a thread',
                            content_type="text/plain",
                            status=403)
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    thread = get_object_or_404(Thread, mailinglist=mlist, thread_id=threadid)
    context = {
        'mlist': mlist,
        'thread': thread,
        'months_list': get_months(mlist),
        'flash_messages': [],
    }
    template_name = "hyperkitty/reattach.html"

    if request.method == 'POST':
        parent_tid = request.POST.get("parent")
        if not parent_tid:
            parent_tid = request.POST.get("parent-manual")
        if not parent_tid or not re.match(r"\w{32}", parent_tid):
            context["flash_messages"].append({
                "type":
                "warning",
                "msg":
                "Invalid thread id, it should look "
                "like OUAASTM6GS4E5TEATD6R2VWMULG44NKJ."
            })
            return render(request, template_name, context)
        if parent_tid == threadid:
            context["flash_messages"].append({
                "type":
                "warning",
                "msg":
                "Can't re-attach a thread to "
                "itself, check your thread ID."
            })
            return render(request, template_name, context)
        try:
            parent = Thread.objects.get(mailinglist=thread.mailinglist,
                                        thread_id=parent_tid)
        except Thread.DoesNotExist:
            context["flash_messages"].append({
                "type":
                "warning",
                "msg":
                "Unknown thread, check your thread ID."
            })
            return render(request, template_name, context)
        try:
            thread.starting_email.set_parent(parent.starting_email)
        except ValueError as e:
            context["flash_messages"].append({"type": "error", "msg": str(e)})
            return render(request, template_name, context)
        return redirect(
            reverse('hk_thread',
                    kwargs={
                        "mlist_fqdn": mlist_fqdn,
                        'threadid': parent_tid,
                    }) + "?msg=attached-ok")
    return render(request, template_name, context)
Example #5
0
def _thread_list(request, mlist, threads, template_name='thread_list.html', extra_context={}):
    if mlist is None:
        raise Http404("No archived mailing-list by that name.")
    store = get_store(request)

    threads = paginate(threads, request.GET.get('page'))

    participants = set()
    for thread in threads:
        if "participants" not in extra_context:
            participants.update(thread.participants)

        # Votes
        set_thread_votes(thread)

        # Favorites
        thread.favorite = False
        if request.user.is_authenticated():
            try:
                Favorite.objects.get(list_address=mlist.name,
                                     threadid=thread.thread_id,
                                     user=request.user)
            except Favorite.DoesNotExist:
                pass
            else:
                thread.favorite = True

        # Tags
        try:
            thread.tags = Tag.objects.filter(threadid=thread.thread_id,
                                             list_address=mlist.name)
        except Tag.DoesNotExist:
            thread.tags = []

        # Category
        thread.category_hk, thread.category_form = \
                get_category_widget(request, thread.category)

        # Unread status
        thread.unread = is_thread_unread(request, mlist.name, thread)

    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = { "type": FLASH_MESSAGES[flash_msg][0],
                      "msg": FLASH_MESSAGES[flash_msg][1] }
        flash_messages.append(flash_msg)

    context = {
        'mlist' : mlist,
        'threads': threads,
        'participants': len(participants),
        'months_list': get_months(store, mlist.name),
        'flash_messages': flash_messages,
    }
    context.update(extra_context)
    return render(request, template_name, context)
Example #6
0
def _thread_list(request, mlist, threads, template_name='thread_list.html', extra_context={}):
    if mlist is None:
        raise Http404("No archived mailing-list by that name.")
    store = get_store(request)

    participants = set()
    for thread in threads:
        participants.update(thread.participants)

        # Votes
        set_thread_votes(thread, request.user)

        # Favorites
        thread.favorite = False
        if request.user.is_authenticated():
            try:
                Favorite.objects.get(list_address=mlist.name,
                                     threadid=thread.thread_id,
                                     user=request.user)
            except Favorite.DoesNotExist:
                pass
            else:
                thread.favorite = True

        # Tags
        try:
            thread.tags = Tag.objects.filter(threadid=thread.thread_id,
                                             list_address=mlist.name)
        except Tag.DoesNotExist:
            thread.tags = []

        # Category
        thread.category_hk, thread.category_form = \
                get_category_widget(request, thread.category)

        # Unread status
        thread.unread = is_thread_unread(request, mlist.name, thread)

    threads = paginate(threads, request.GET.get('page'))

    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = { "type": FLASH_MESSAGES[flash_msg][0],
                      "msg": FLASH_MESSAGES[flash_msg][1] }
        flash_messages.append(flash_msg)

    context = {
        'mlist' : mlist,
        'threads': threads,
        'participants': len(participants),
        'months_list': get_months(store, mlist.name),
        'flash_messages': flash_messages,
    }
    context.update(extra_context)
    return render(request, template_name, context)
Example #7
0
def reattach(request, mlist_fqdn, threadid):
    if not request.user.is_staff:
        return HttpResponse('You must be a staff member to reattach a thread',
                            content_type="text/plain", status=403)
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    thread = get_object_or_404(Thread, mailinglist=mlist, thread_id=threadid)
    context = {
        'mlist': mlist,
        'thread': thread,
        'months_list': get_months(mlist),
        'flash_messages': [],
    }
    template_name = "hyperkitty/reattach.html"

    if request.method == 'POST':
        parent_tid = request.POST.get("parent")
        if not parent_tid:
            parent_tid = request.POST.get("parent-manual")
        if not parent_tid or not re.match(r"\w{32}", parent_tid):
            context["flash_messages"].append(
                {"type": "warning",
                 "msg": "Invalid thread id, it should look "
                        "like OUAASTM6GS4E5TEATD6R2VWMULG44NKJ."})
            return render(request, template_name, context)
        if parent_tid == threadid:
            context["flash_messages"].append(
                {"type": "warning",
                 "msg": "Can't re-attach a thread to "
                        "itself, check your thread ID."})
            return render(request, template_name, context)
        try:
            parent = Thread.objects.get(
                mailinglist=thread.mailinglist, thread_id=parent_tid)
        except Thread.DoesNotExist:
            context["flash_messages"].append(
                {"type": "warning",
                 "msg": "Unknown thread, check your thread ID."})
            return render(request, template_name, context)
        try:
            thread.starting_email.set_parent(parent.starting_email)
        except ValueError as e:
            context["flash_messages"].append({"type": "error", "msg": str(e)})
            return render(request, template_name, context)
        return redirect(reverse(
                'hk_thread', kwargs={
                    "mlist_fqdn": mlist_fqdn,
                    'threadid': parent_tid,
                })+"?msg=attached-ok")
    return render(request, template_name, context)
Example #8
0
def reattach(request, mlist_fqdn, threadid):
    if not request.user.is_staff:
        return HttpResponse('You must be a staff member to reattach a thread',
                            content_type="text/plain", status=403)
    flash_messages = []
    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    thread = store.get_thread(mlist_fqdn, threadid)

    if request.method == 'POST':
        parent_tid = request.POST.get("parent")
        if not parent_tid:
            parent_tid = request.POST.get("parent-manual")
        if not parent_tid or not re.match("\w{32}", parent_tid):
            flash_messages.append({"type": "warning",
                                   "msg": "Invalid thread id, it should look "
                                          "like OUAASTM6GS4E5TEATD6R2VWMULG44NKJ."})
        elif parent_tid == threadid:
            flash_messages.append({"type": "warning",
                                   "msg": "Can't re-attach a thread to "
                                          "itself, check your thread ID."})
        else:
            new_thread = store.get_thread(mlist_fqdn, parent_tid)
            if new_thread is None:
                flash_messages.append({"type": "warning",
                                       "msg": "Unknown thread, check your "
                                              "thread ID."})
            elif thread.starting_email.date <= new_thread.starting_email.date:
                flash_messages.append({"type": "error",
                                       "msg": "Can't attach an older thread "
                                              "to a newer thread."})
            else:
                for msg in thread.emails:
                    store.attach_to_thread(msg, new_thread)
                store.delete_thread(mlist_fqdn, threadid)
                return redirect(reverse(
                        'thread', kwargs={
                            "mlist_fqdn": mlist_fqdn,
                            'threadid': parent_tid,
                        })+"?msg=attached-ok")


    context = {
        'mlist' : mlist,
        'thread': thread,
        'months_list': get_months(store, mlist.name),
        'flash_messages': flash_messages,
    }
    return render(request, "reattach.html", context)
Example #9
0
def _thread_list(request,
                 mlist,
                 threads,
                 template_name='hyperkitty/thread_list.html',
                 extra_context=None):
    categories = [ (c.name, c.name.upper())
                   for c in ThreadCategory.objects.all() ] \
                 + [("", "no category")]
    threads = paginate(threads,
                       request.GET.get('page'),
                       results_per_page=request.GET.get('count'))
    for thread in threads:
        # Favorites
        thread.favorite = False
        if request.user.is_authenticated():
            try:
                Favorite.objects.get(thread=thread, user=request.user)
            except Favorite.DoesNotExist:
                pass
            else:
                thread.favorite = True
        # Category
        thread.category_hk, thread.category_form = \
            get_category_widget(request, thread.category, categories)

    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = {
            "type": FLASH_MESSAGES[flash_msg][0],
            "msg": FLASH_MESSAGES[flash_msg][1]
        }
        flash_messages.append(flash_msg)

    context = {
        'mlist': mlist,
        'threads': threads,
        'months_list': get_months(mlist),
        'flash_messages': flash_messages,
        'per_page_options': [10, 50, 100, 200],
    }
    if extra_context is not None:
        context.update(extra_context)
    return render(request, template_name, context)
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    authors = []

    # Threads by category
    threads_by_category = {}

    # Export button
    recent_dates = [d.strftime("%Y-%m-%d") for d in mlist.get_recent_dates()]
    recent_url = "%s?start=%s&end=%s" % (reverse(
        "hk_list_export_mbox",
        kwargs={
            "mlist_fqdn": mlist.name,
            "filename": "%s-%s-%s" %
            (mlist.name, recent_dates[0], recent_dates[1])
        }), recent_dates[0], recent_dates[1])
    today = datetime.date.today()
    month_dates = get_display_dates(today.year, today.month, None)
    month_url = "%s?start=%s&end=%s" % (reverse(
        "hk_list_export_mbox",
        kwargs={
            "mlist_fqdn": mlist.name,
            "filename": "%s-%s" % (mlist.name, today.strftime("%Y-%m"))
        }), month_dates[0].strftime("%Y-%m-%d"),
                                        month_dates[1].strftime("%Y-%m-%d"))
    export = {"recent": recent_url, "month": month_url}

    context = {
        'view_name': 'overview',
        'mlist': mlist,
        'top_author': authors,
        'threads_by_category': threads_by_category,
        'months_list': get_months(mlist),
        'export': export,
        'posting_enabled': getattr(settings, 'HYPERKITTY_ALLOW_WEB_POSTING',
                                   True),
    }
    return render(request, "hyperkitty/overview.html", context)
def index(request, mlist_fqdn, message_id_hash):
    '''
    Displays a single message identified by its message_id_hash (derived from
    message_id)
    '''
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    message = get_object_or_404(Email,
                                mailinglist=mlist,
                                message_id_hash=message_id_hash)
    if request.user.is_authenticated:
        message.myvote = message.votes.filter(user=request.user).first()
    else:
        message.myvote = None

    # Export button
    export = {
        "url":
        "%s?message=%s" %
        (reverse("hk_list_export_mbox",
                 kwargs={
                     "mlist_fqdn": mlist.name,
                     "filename": "%s-%s" %
                     (mlist.name, message.message_id_hash)
                 }), message.message_id_hash),
        "message":
        _("Download"),
        "title":
        _("This message in gzipped mbox format"),
    }

    context = {
        'mlist': mlist,
        'message': message,
        'message_id_hash': message_id_hash,
        'months_list': get_months(mlist),
        'month': message.date,
        'reply_form': get_posting_form(ReplyForm, request, mlist),
        'export': export,
        'posting_enabled': getattr(settings, 'HYPERKITTY_ALLOW_WEB_POSTING',
                                   True),
    }
    return render(request, "hyperkitty/message.html", context)
def new_message(request, mlist_fqdn):
    """ Sends a new thread-starting message to the list. """
    if not getattr(settings, 'HYPERKITTY_ALLOW_WEB_POSTING', True):
        return HttpResponse('Posting via Hyperkitty is disabled',
                            content_type="text/plain",
                            status=403)
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    if request.method == 'POST':
        form = get_posting_form(PostForm, request, mlist, request.POST)
        if form.is_valid():
            today = datetime.date.today()
            headers = {}
            if form.cleaned_data["sender"]:
                headers["From"] = form.cleaned_data["sender"]
            try:
                post_to_list(request, mlist, form.cleaned_data['subject'],
                             form.cleaned_data["message"], headers)
            except PostingFailed as e:
                messages.error(request, str(e))
            except ModeratedListException as e:
                return HttpResponse(str(e),
                                    content_type="text/plain",
                                    status=403)
            else:
                messages.success(request,
                                 "The message has been sent successfully.")
                redirect_url = reverse('hk_archives_with_month',
                                       kwargs={
                                           "mlist_fqdn": mlist_fqdn,
                                           'year': today.year,
                                           'month': today.month
                                       })
                return redirect(redirect_url)
    else:
        form = get_posting_form(PostForm, request, mlist)
    context = {
        "mlist": mlist,
        "post_form": form,
        'months_list': get_months(mlist),
    }
    return render(request, "hyperkitty/message_new.html", context)
Example #13
0
def index(request, mlist_fqdn, message_id_hash):
    '''
    Displays a single message identified by its message_id_hash (derived from
    message_id)
    '''
    store = get_store(request)
    message = store.get_message_by_hash_from_list(mlist_fqdn, message_id_hash)
    if message is None:
        raise Http404
    message.sender_email = message.sender_email.strip()
    set_message_votes(message, request.user)
    mlist = store.get_list(mlist_fqdn)

    context = {
        'mlist': mlist,
        'message': message,
        'message_id_hash': message_id_hash,
        'months_list': get_months(store, mlist.name),
        'reply_form': ReplyForm(),
    }
    return render(request, "message.html", context)
Example #14
0
def index(request, mlist_fqdn, message_id_hash):
    '''
    Displays a single message identified by its message_id_hash (derived from
    message_id)
    '''
    store = get_store(request)
    message = store.get_message_by_hash_from_list(mlist_fqdn, message_id_hash)
    if message is None:
        raise Http404
    message.sender_email = message.sender_email.strip()
    message.myvote = message.get_vote_by_user_id(request.session.get("user_id"))
    mlist = store.get_list(mlist_fqdn)

    context = {
        'mlist' : mlist,
        'message': message,
        'message_id_hash' : message_id_hash,
        'months_list': get_months(store, mlist.name),
        'reply_form': ReplyForm(),
    }
    return render(request, "message.html", context)
Example #15
0
def index(request, mlist_fqdn, message_id_hash):
    """
    Displays a single message identified by its message_id_hash (derived from
    message_id)
    """
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    message = get_object_or_404(Email, mailinglist=mlist, message_id_hash=message_id_hash)
    if request.user.is_authenticated():
        message.myvote = message.votes.filter(user=request.user).first()
    else:
        message.myvote = None

    context = {
        "mlist": mlist,
        "message": message,
        "message_id_hash": message_id_hash,
        "months_list": get_months(mlist),
        "month": message.date,
        "reply_form": ReplyForm(),
    }
    return render(request, "hyperkitty/message.html", context)
Example #16
0
def index(request, mlist_fqdn, message_id_hash):
    '''
    Displays a single message identified by its message_id_hash (derived from
    message_id)
    '''
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    message = get_object_or_404(Email,
                                mailinglist=mlist,
                                message_id_hash=message_id_hash)
    if request.user.is_authenticated():
        message.myvote = message.votes.filter(user=request.user).first()
    else:
        message.myvote = None

    context = {
        'mlist': mlist,
        'message': message,
        'message_id_hash': message_id_hash,
        'months_list': get_months(mlist),
        'month': message.date,
        'reply_form': ReplyForm(),
    }
    return render(request, "hyperkitty/message.html", context)
Example #17
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')

    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    if mlist is None:
        raise Http404("No archived mailing-list by that name.")
    begin_date, end_date = mlist.get_recent_dates()
    threads_result = store.get_threads(
            list_name=mlist.name, start=begin_date, end=end_date)

    threads = []
    for thread_obj in threads_result:
        thread_obj.category_widget = get_category_widget(
                None, thread_obj.category)[0]
        thread_obj.unread = is_thread_unread(request, mlist.name, thread_obj)
        threads.append(thread_obj)

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: len(t), reverse=True)

    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if settings.USE_MOCKUPS:
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Top posters
    top_posters = []
    for poster in store.get_top_participants(list_name=mlist.name,
                start=begin_date, end=end_date, limit=5):
        top_posters.append({"name": poster[0], "email": poster[1],
                            "count": poster[2]})

    # Popular threads
    pop_threads = sorted([ t for t in threads if t.likes - t.dislikes > 0 ],
                         key=lambda t: t.likes - t.dislikes,
                         reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    context = {
        'view_name': 'overview',
        'mlist' : mlist,
        'top_threads': top_threads[:5],
        'most_active_threads': active_threads[:5],
        'top_author': authors,
        'top_posters': top_posters,
        'pop_threads': pop_threads[:5],
        'threads_by_category': threads_by_category,
        'months_list': get_months(store, mlist.name),
    }
    return render(request, "overview.html", context)
Example #18
0
    """ Sends a new thread-starting message to the list. """
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    failure = None
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            today = datetime.date.today()
            redirect_url = reverse('hk_archives_with_month',
                                   kwargs={
                                       "mlist_fqdn": mlist_fqdn,
                                       'year': today.year,
                                       'month': today.month
                                   })
            redirect_url += "?msg=sent-ok"
            try:
                post_to_list(request, mlist, form.cleaned_data['subject'],
                             form.cleaned_data["message"])
            except PostingFailed, e:
                failure = str(e)
            else:
                return redirect(redirect_url)
    else:
        form = PostForm()
    context = {
        "mlist": mlist,
        "post_form": form,
        "failure": failure,
        'months_list': get_months(mlist),
    }
    return render(request, "hyperkitty/message_new.html", context)
Example #19
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    threads = mlist.recent_threads

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: t.emails_count, reverse=True)
    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if getattr(settings, 'USE_MOCKUPS', False):
        from hyperkitty.lib.mockup import generate_top_author
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Popular threads
    pop_threads = []
    for t in threads:
        votes = t.get_votes()
        if votes["likes"] - votes["dislikes"] > 0:
            pop_threads.append(t)
    def _get_thread_vote_result(t):
        votes = t.get_votes()
        return votes["likes"] - votes["dislikes"]
    pop_threads.sort(key=_get_thread_vote_result, reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    # Personalized discussion groups: flagged/favorited threads and threads by user
    if request.user.is_authenticated():
        favorites = [ f.thread for f in Favorite.objects.filter(
            thread__mailinglist=mlist, user=request.user) ]
        mm_user_id = request.user.hyperkitty_profile.get_mailman_user_id()
        threads_posted_to = []
        if mm_user_id is not None:
            for thread in threads:
                senders = set([e.sender.mailman_id for e in thread.emails.all()])
                if mm_user_id in senders:
                    threads_posted_to.append(thread)
    else:
        favorites = []
        threads_posted_to = []

    # Empty messages # TODO: translate this
    empty_messages = {
        "flagged": 'You have not flagged any discussions (yet).',
        "posted": 'You have not posted to this list (yet).',
        "active": 'No discussions this month (yet).',
        "popular": 'No vote has been cast this month (yet).',
    }

    # Export button
    recent_dates = [
        d.strftime("%Y-%m-%d") for d in mlist.get_recent_dates() ]
    recent_url = "%s?start=%s&end=%s" % (
        reverse("hk_list_export_mbox", kwargs={
                "mlist_fqdn": mlist.name,
                "filename": "%s-%s-%s" % (
                    mlist.name, recent_dates[0], recent_dates[1])}),
        recent_dates[0], recent_dates[1])
    today = datetime.date.today()
    month_dates = get_display_dates(today.year, today.month, None)
    month_url = "%s?start=%s&end=%s" % (
        reverse("hk_list_export_mbox", kwargs={
                "mlist_fqdn": mlist.name,
                "filename": "%s-%s" % (mlist.name, today.strftime("%Y-%m"))}),
        month_dates[0].strftime("%Y-%m-%d"),
        month_dates[1].strftime("%Y-%m-%d"))
    export = {"recent": recent_url, "month": month_url}

    context = {
        'view_name': 'overview',
        'mlist' : mlist,
        'top_threads': top_threads[:20],
        'most_active_threads': active_threads[:20],
        'top_author': authors,
        'pop_threads': pop_threads[:20],
        'threads_by_category': threads_by_category,
        'months_list': get_months(mlist),
        'flagged_threads': favorites,
        'threads_posted_to': threads_posted_to,
        'empty_messages': empty_messages,
        'export': export,
    }
    return render(request, "hyperkitty/overview.html", context)
Example #20
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')

    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    if mlist is None:
        raise Http404("No archived mailing-list by that name.")
    begin_date, end_date = mlist.get_recent_dates()
    threads_result = store.get_threads(
            list_name=mlist.name, start=begin_date, end=end_date)

    threads = []
    for thread_obj in threads_result:
        # Votes
        set_thread_votes(thread_obj)
        thread_obj.category_widget = get_category_widget(
                None, thread_obj.category)[0]
        thread_obj.unread = is_thread_unread(request, mlist.name, thread_obj)
        threads.append(thread_obj)

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: len(t), reverse=True)

    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if settings.USE_MOCKUPS:
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Top posters
    top_posters = []
    for poster in store.get_top_participants(list_name=mlist.name,
                start=begin_date, end=end_date, limit=5):
        top_posters.append({"name": poster[0], "email": poster[1],
                            "count": poster[2]})

    # Popular threads
    pop_threads = sorted([ t for t in threads if t.likes - t.dislikes > 0 ],
                         key=lambda t: t.likes - t.dislikes,
                         reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    context = {
        'view_name': 'overview',
        'mlist' : mlist,
        'top_threads': top_threads[:5],
        'most_active_threads': active_threads[:5],
        'top_author': authors,
        'top_posters': top_posters,
        'pop_threads': pop_threads[:5],
        'threads_by_category': threads_by_category,
        'months_list': get_months(store, mlist.name),
    }
    return render(request, "overview.html", context)
Example #21
0
def reattach(request, mlist_fqdn, threadid):
    if not request.user.is_staff:
        return HttpResponse('You must be a staff member to reattach a thread',
                            content_type="text/plain",
                            status=403)
    flash_messages = []
    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    thread = store.get_thread(mlist_fqdn, threadid)

    if request.method == 'POST':
        parent_tid = request.POST.get("parent")
        if not parent_tid:
            parent_tid = request.POST.get("parent-manual")
        if not parent_tid or not re.match("\w{32}", parent_tid):
            flash_messages.append({
                "type":
                "warning",
                "msg":
                "Invalid thread id, it should look "
                "like OUAASTM6GS4E5TEATD6R2VWMULG44NKJ."
            })
        elif parent_tid == threadid:
            flash_messages.append({
                "type":
                "warning",
                "msg":
                "Can't re-attach a thread to "
                "itself, check your thread ID."
            })
        else:
            new_thread = store.get_thread(mlist_fqdn, parent_tid)
            if new_thread is None:
                flash_messages.append({
                    "type":
                    "warning",
                    "msg":
                    "Unknown thread, check your "
                    "thread ID."
                })
            elif thread.starting_email.date <= new_thread.starting_email.date:
                flash_messages.append({
                    "type":
                    "error",
                    "msg":
                    "Can't attach an older thread "
                    "to a newer thread."
                })
            else:
                for msg in thread.emails:
                    store.attach_to_thread(msg, new_thread)
                store.delete_thread(mlist_fqdn, threadid)
                return redirect(
                    reverse('thread',
                            kwargs={
                                "mlist_fqdn": mlist_fqdn,
                                'threadid': parent_tid,
                            }) + "?msg=attached-ok")

    context = {
        'mlist': mlist,
        'thread': thread,
        'months_list': get_months(store, mlist.name),
        'flash_messages': flash_messages,
    }
    return render(request, "reattach.html", context)
Example #22
0
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
    ''' Displays all the email for a given thread identifier '''
    # pylint: disable=unused-argument
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    thread = get_object_or_404(Thread, mailinglist=mlist, thread_id=threadid)
    starting_email = thread.starting_email

    sort_mode = request.GET.get("sort", "thread")
    if request.user.is_authenticated():
        starting_email.myvote = starting_email.votes.filter(
            user=request.user).first()
    else:
        starting_email.myvote = None

    # Tags
    tag_form = AddTagForm()

    # Favorites
    fav_action = "add"
    if request.user.is_authenticated() and Favorite.objects.filter(
            thread=thread, user=request.user).exists():
        fav_action = "rm"

    # Category
    categories = [ (c.name, c.name.upper())
                   for c in ThreadCategory.objects.all() ] \
                 + [("", "no category")]
    category, category_form = get_category_widget(
        request, thread.category, categories)

    # Extract relative dates
    today = datetime.date.today()
    days_old = today - starting_email.date.date()
    days_inactive = today - thread.date_active.date()

    subject = stripped_subject(mlist, starting_email.subject)

    # Last view
    last_view = None
    if request.user.is_authenticated():
        last_view_obj, created = LastView.objects.get_or_create(
                thread=thread, user=request.user)
        if not created:
            last_view = last_view_obj.view_date
            last_view_obj.save() # update timestamp
    # get the number of unread messages
    if last_view is None:
        if request.user.is_authenticated():
            unread_count = thread.emails_count
        else:
            unread_count = 0
    else:
        unread_count = thread.emails.filter(date__gt=last_view).count()

    # Flash messages
    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = { "type": FLASH_MESSAGES[flash_msg][0],
                      "msg": FLASH_MESSAGES[flash_msg][1] }
        flash_messages.append(flash_msg)

    # TODO: eventually move to a middleware ?
    # http://djangosnippets.org/snippets/1865/
    user_agent = request.META.get('HTTP_USER_AGENT', None)
    if user_agent:
        is_bot = robot_detection.is_robot(user_agent)
    else:
        is_bot = True

    context = {
        'mlist': mlist,
        'thread': thread,
        'starting_email': starting_email,
        'subject': subject,
        'addtag_form': tag_form,
        'month': thread.date_active,
        'months_list': get_months(mlist),
        'days_inactive': days_inactive.days,
        'days_old': days_old.days,
        'sort_mode': sort_mode,
        'fav_action': fav_action,
        'reply_form': ReplyForm(),
        'is_bot': is_bot,
        'num_comments': thread.emails_count - 1,
        'last_view': last_view,
        'unread_count': unread_count,
        'category_form': category_form,
        'category': category,
        'flash_messages': flash_messages,
    }

    if is_bot:
        # Don't rely on AJAX to load the replies
        # The limit is a safety measure, don't let a bot kill the DB
        context["replies"] = _get_thread_replies(request, thread, limit=1000)

    return render(request, "hyperkitty/thread.html", context)
Example #23
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')

    # Get stats for last 30 days
    today = datetime.datetime.utcnow()
    #today -= datetime.timedelta(days=365) #debug
    # the upper boundary is excluded in the search, add one day
    end_date = today + datetime.timedelta(days=1)
    begin_date = end_date - datetime.timedelta(days=32)

    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    if mlist is None:
        raise Http404("No archived mailing-list by that name.")
    threads_result = store.get_threads(
            list_name=mlist.name, start=begin_date, end=end_date)

    threads = []
    participants = set()
    for thread_obj in threads_result:
        # Votes
        set_thread_votes(thread_obj, request.user)
        thread = Thread(thread_obj.thread_id, thread_obj.subject,
                        thread_obj.participants, len(thread_obj),
                        thread_obj.date_active.replace(tzinfo=utc),
                        thread_obj.likes, thread_obj.dislikes,
                        thread_obj.likestatus,
                        get_category_widget(None, thread_obj.category)[0],
                        is_thread_unread(request, mlist.name, thread_obj),
                        )
        # Statistics on how many participants and threads this month
        participants.update(thread.participants)
        threads.append(thread)

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: t.length, reverse=True)

    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if settings.USE_MOCKUPS:
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Top posters
    top_posters = []
    for poster in store.get_top_participants(list_name=mlist.name,
                start=begin_date, end=end_date, limit=5):
        top_posters.append({"name": poster[0], "email": poster[1],
                            "count": poster[2]})

    # Popular threads
    pop_threads = sorted([ t for t in threads if t.likes - t.dislikes > 0 ],
                         key=lambda t: t.likes - t.dislikes,
                         reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    # List activity
    # Use get_messages and not get_threads to count the emails, because
    # recently active threads include messages from before the start date
    emails_in_month = store.get_messages(list_name=mlist.name,
                                         start=begin_date, end=end_date)
    # graph
    dates = defaultdict(lambda: 0) # no activity by default
    # populate with all days before adding data.
    for single_date in daterange(begin_date, end_date):
        dates[single_date.strftime("%Y-%m-%d")] = 0

    for email in emails_in_month:
        date_str = email.date.strftime("%Y-%m-%d")
        dates[date_str] = dates[date_str] + 1
    days = dates.keys()
    days.sort()
    evolution = [dates[d] for d in days]
    if not evolution:
        evolution.append(0)
    archives_baseurl = reverse("archives_latest",
                               kwargs={'mlist_fqdn': mlist.name})
    archives_baseurl = archives_baseurl.rpartition("/")[0]

    context = {
        'view_name': 'overview',
        'mlist' : mlist,
        'top_threads': top_threads[:5],
        'most_active_threads': active_threads[:5],
        'top_author': authors,
        'top_posters': top_posters,
        'pop_threads': pop_threads[:5],
        'threads_by_category': threads_by_category,
        'months_list': get_months(store, mlist.name),
        'evolution': evolution,
        'days': days,
        'archives_baseurl': archives_baseurl,
        'num_threads': len(threads),
        'num_participants': len(participants),
    }
    return render(request, "overview.html", context)
Example #24
0
def new_message(request, mlist_fqdn):
    """ Sends a new thread-starting message to the list. """
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    failure = None
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            today = datetime.date.today()
            redirect_url = reverse(
                    'hk_archives_with_month', kwargs={
                        "mlist_fqdn": mlist_fqdn,
                        'year': today.year,
                        'month': today.month})
            redirect_url += "?msg=sent-ok"
            try:
                post_to_list(request, mlist, form.cleaned_data['subject'],
                             form.cleaned_data["message"])
            except PostingFailed, e:
                failure = str(e)
            else:
                return redirect(redirect_url)
    else:
        form = PostForm()
    context = {
        "mlist": mlist,
        "post_form": form,
        "failure": failure,
        'months_list': get_months(mlist),
    }
    return render(request, "hyperkitty/message_new.html", context)
Example #25
0
    """ Sends a new thread-starting message to the list.
    TODO: unit tests
    """
    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    failure = None
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            today = datetime.date.today()
            redirect_url = reverse(
                "archives_with_month", kwargs={"mlist_fqdn": mlist_fqdn, "year": today.year, "month": today.month}
            )
            redirect_url += "?msg=sent-ok"
            try:
                post_to_list(
                    request,
                    mlist,
                    form.cleaned_data["subject"],
                    form.cleaned_data["message"],
                    attachments=request.FILES.getlist("attachment"),
                )
            except PostingFailed, e:
                failure = str(e)
            else:
                return redirect(redirect_url)
    else:
        form = PostForm()
    context = {"mlist": mlist, "post_form": form, "failure": failure, "months_list": get_months(store, mlist.name)}
    return render(request, "message_new.html", context)
Example #26
0
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
    ''' Displays all the email for a given thread identifier '''
    store = get_store(request)
    thread = store.get_thread(mlist_fqdn, threadid)
    if not thread:
        raise Http404
    prev_thread, next_thread = store.get_thread_neighbors(mlist_fqdn, threadid)

    sort_mode = request.GET.get("sort", "thread")
    set_message_votes(thread.starting_email, request.user)

    # Tags
    tag_form = AddTagForm()
    try:
        tags = Tag.objects.filter(threadid=threadid, list_address=mlist_fqdn)
    except Tag.DoesNotExist:
        tags = []

    # Favorites
    fav_action = "add"
    if request.user.is_authenticated():
        try:
            Favorite.objects.get(list_address=mlist_fqdn, threadid=threadid,
                                 user=request.user)
        except Favorite.DoesNotExist:
            pass
        else:
            fav_action = "rm"

    # Category
    category, category_form = get_category_widget(request, thread.category)

    # Extract relative dates
    today = datetime.date.today()
    days_old = today - thread.starting_email.date.date()
    days_inactive = today - thread.last_email.date.date()

    mlist = store.get_list(mlist_fqdn)
    subject = stripped_subject(mlist, thread.starting_email.subject)

    # Last view
    last_view = None
    if request.user.is_authenticated():
        last_view_obj, created = LastView.objects.get_or_create(
                list_address=mlist_fqdn, threadid=threadid, user=request.user)
        if not created:
            last_view = last_view_obj.view_date
            last_view_obj.save() # update timestamp
    # get the number of unread messages
    if last_view is None:
        if request.user.is_authenticated():
            unread_count = len(thread)
        else:
            unread_count = 0
    else:
        # XXX: Storm-specific
        unread_count = thread.replies_after(last_view).count()

    # Flash messages
    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = { "type": FLASH_MESSAGES[flash_msg][0],
                      "msg": FLASH_MESSAGES[flash_msg][1] }
        flash_messages.append(flash_msg)

    # TODO: eventually move to a middleware ?
    # http://djangosnippets.org/snippets/1865/
    is_bot = True
    user_agent = request.META.get('HTTP_USER_AGENT', None)
    if user_agent:
        is_bot = robot_detection.is_robot(user_agent)

    context = {
        'mlist': mlist,
        'threadid': threadid,
        'subject': subject,
        'tags': tags,
        'addtag_form': tag_form,
        'month': thread.date_active,
        'first_mail': thread.starting_email,
        'neighbors': (prev_thread, next_thread),
        'months_list': get_months(store, mlist.name),
        'days_inactive': days_inactive.days,
        'days_old': days_old.days,
        'sort_mode': sort_mode,
        'fav_action': fav_action,
        'reply_form': ReplyForm(),
        'is_bot': is_bot,
        'num_comments': len(thread),
        'participants': thread.participants,
        'last_view': last_view,
        'unread_count': unread_count,
        'category_form': category_form,
        'category': category,
        'flash_messages': flash_messages,
    }
    context["participants"].sort(key=lambda x: x[0].lower())

    if is_bot:
        # Don't rely on AJAX to load the replies
        # The limit is a safety measure, don't let a bot kill the DB
        context["replies"] = _get_thread_replies(request, thread, limit=1000)

    return render(request, "thread.html", context)
Example #27
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    threads = []
    for thread_obj in mlist.recent_threads:
        thread_obj.category_widget = get_category_widget(
            None, thread_obj.category)[0]
        threads.append(thread_obj)

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: t.emails_count, reverse=True)

    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if settings.USE_MOCKUPS:
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Popular threads
    pop_threads = []
    for t in threads:
        votes = t.get_votes()
        if votes["likes"] - votes["dislikes"] > 0:
            pop_threads.append(t)

    def _get_thread_vote_result(t):
        votes = t.get_votes()
        return votes["likes"] - votes["dislikes"]

    pop_threads.sort(key=_get_thread_vote_result, reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    # Personalized discussion groups: flagged/favorited threads and threads by user
    if request.user.is_authenticated():
        favorites = [
            f.thread
            for f in Favorite.objects.filter(thread__mailinglist=mlist,
                                             user=request.user)
        ]
        mm_user_id = request.user.hyperkitty_profile.get_mailman_user_id()
        threads_posted_to = []
        if mm_user_id is not None:
            for thread in threads:
                senders = set(
                    [e.sender.mailman_id for e in thread.emails.all()])
                if mm_user_id in senders:
                    threads_posted_to.append(thread)
    else:
        favorites = []
        threads_posted_to = []

    # Empty messages # TODO: translate this
    empty_messages = {
        "flagged": 'You have not flagged any discussions (yet).',
        "posted": 'You have not posted to this list (yet).',
        "active": 'No discussions this month (yet).',
        "popular": 'No vote has been cast this month (yet).',
    }

    context = {
        'view_name': 'overview',
        'mlist': mlist,
        'top_threads': top_threads[:20],
        'most_active_threads': active_threads[:20],
        'top_author': authors,
        'pop_threads': pop_threads[:20],
        'threads_by_category': threads_by_category,
        'months_list': get_months(mlist),
        'flagged_threads': favorites,
        'threads_posted_to': threads_posted_to,
        'empty_messages': empty_messages,
    }
    return render(request, "hyperkitty/overview.html", context)
Example #28
0
    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    failure = None
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            today = datetime.date.today()
            redirect_url = reverse(
                    'archives_with_month', kwargs={
                        "mlist_fqdn": mlist_fqdn,
                        'year': today.year,
                        'month': today.month})
            redirect_url += "?msg=sent-ok"
            try:
                post_to_list(request, mlist, form.cleaned_data['subject'],
                             form.cleaned_data["message"],
                             attachments=request.FILES.getlist("attachment"))
            except PostingFailed, e:
                failure = str(e)
            else:
                return redirect(redirect_url)
    else:
        form = PostForm()
    context = {
        "mlist": mlist,
        "post_form": form,
        "failure": failure,
        'months_list': get_months(store, mlist.name),
    }
    return render(request, "message_new.html", context)
Example #29
0
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
    ''' Displays all the email for a given thread identifier '''
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    thread = get_object_or_404(Thread, mailinglist=mlist, thread_id=threadid)
    starting_email = thread.starting_email

    sort_mode = request.GET.get("sort", "thread")
    if request.user.is_authenticated():
        starting_email.myvote = starting_email.votes.filter(
            user=request.user).first()
    else:
        starting_email.myvote = None

    # Tags
    tag_form = AddTagForm()

    # Favorites
    fav_action = "add"
    if request.user.is_authenticated() and Favorite.objects.filter(
            thread=thread, user=request.user).exists():
        fav_action = "rm"

    # Category
    category, category_form = get_category_widget(request, thread.category)

    # Extract relative dates
    today = datetime.date.today()
    days_old = today - starting_email.date.date()
    days_inactive = today - thread.date_active.date()

    subject = stripped_subject(mlist, starting_email.subject)

    # Last view
    last_view = None
    if request.user.is_authenticated():
        last_view_obj, created = LastView.objects.get_or_create(
            thread=thread, user=request.user)
        if not created:
            last_view = last_view_obj.view_date
            last_view_obj.save()  # update timestamp
    # get the number of unread messages
    if last_view is None:
        if request.user.is_authenticated():
            unread_count = thread.emails_count
        else:
            unread_count = 0
    else:
        unread_count = thread.emails.filter(date__gt=last_view).count()

    # TODO: eventually move to a middleware ?
    # http://djangosnippets.org/snippets/1865/
    user_agent = request.META.get('HTTP_USER_AGENT', None)
    if user_agent:
        is_bot = robot_detection.is_robot(user_agent)
    else:
        is_bot = True

    # Export button
    export = {
        "url":
        "%s?thread=%s" %
        (reverse("hk_list_export_mbox",
                 kwargs={
                     "mlist_fqdn": mlist.name,
                     "filename": "%s-%s" % (mlist.name, thread.thread_id)
                 }), thread.thread_id),
        "message":
        _("Download"),
        "title":
        _("This thread in gzipped mbox format"),
    }

    context = {
        'mlist': mlist,
        'thread': thread,
        'starting_email': starting_email,
        'subject': subject,
        'addtag_form': tag_form,
        'month': thread.date_active,
        'months_list': get_months(mlist),
        'days_inactive': days_inactive.days,
        'days_old': days_old.days,
        'sort_mode': sort_mode,
        'fav_action': fav_action,
        'reply_form': get_posting_form(ReplyForm, request, mlist),
        'is_bot': is_bot,
        'num_comments': thread.emails_count - 1,
        'last_view': last_view,
        'unread_count': unread_count,
        'category_form': category_form,
        'category': category,
        'export': export,
    }

    if is_bot:
        # Don't rely on AJAX to load the replies
        # The limit is a safety measure, don't let a bot kill the DB
        context["replies"] = _get_thread_replies(request, thread, limit=1000)

    return render(request, "hyperkitty/thread.html", context)
Example #30
0
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
    ''' Displays all the email for a given thread identifier '''
    # pylint: disable=unused-argument
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    thread = get_object_or_404(Thread, mailinglist=mlist, thread_id=threadid)
    starting_email = thread.starting_email

    sort_mode = request.GET.get("sort", "thread")
    if request.user.is_authenticated():
        starting_email.myvote = starting_email.votes.filter(
            user=request.user).first()
    else:
        starting_email.myvote = None

    # Tags
    tag_form = AddTagForm()

    # Favorites
    fav_action = "add"
    if request.user.is_authenticated() and Favorite.objects.filter(
            thread=thread, user=request.user).exists():
        fav_action = "rm"

    # Category
    categories = [ (c.name, c.name.upper())
                   for c in ThreadCategory.objects.all() ] \
                 + [("", "no category")]
    category, category_form = get_category_widget(request, thread.category,
                                                  categories)

    # Extract relative dates
    today = datetime.date.today()
    days_old = today - starting_email.date.date()
    days_inactive = today - thread.date_active.date()

    subject = stripped_subject(mlist, starting_email.subject)

    # Last view
    last_view = None
    if request.user.is_authenticated():
        last_view_obj, created = LastView.objects.get_or_create(
            thread=thread, user=request.user)
        if not created:
            last_view = last_view_obj.view_date
            last_view_obj.save()  # update timestamp
    # get the number of unread messages
    if last_view is None:
        if request.user.is_authenticated():
            unread_count = thread.emails_count
        else:
            unread_count = 0
    else:
        unread_count = thread.emails.filter(date__gt=last_view).count()

    # Flash messages
    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = {
            "type": FLASH_MESSAGES[flash_msg][0],
            "msg": FLASH_MESSAGES[flash_msg][1]
        }
        flash_messages.append(flash_msg)

    # TODO: eventually move to a middleware ?
    # http://djangosnippets.org/snippets/1865/
    user_agent = request.META.get('HTTP_USER_AGENT', None)
    if user_agent:
        is_bot = robot_detection.is_robot(user_agent)
    else:
        is_bot = True

    context = {
        'mlist': mlist,
        'thread': thread,
        'starting_email': starting_email,
        'subject': subject,
        'addtag_form': tag_form,
        'month': thread.date_active,
        'months_list': get_months(mlist),
        'days_inactive': days_inactive.days,
        'days_old': days_old.days,
        'sort_mode': sort_mode,
        'fav_action': fav_action,
        'reply_form': ReplyForm(),
        'is_bot': is_bot,
        'num_comments': thread.emails_count - 1,
        'last_view': last_view,
        'unread_count': unread_count,
        'category_form': category_form,
        'category': category,
        'flash_messages': flash_messages,
    }

    if is_bot:
        # Don't rely on AJAX to load the replies
        # The limit is a safety measure, don't let a bot kill the DB
        context["replies"] = _get_thread_replies(request, thread, limit=1000)

    return render(request, "hyperkitty/thread.html", context)
Example #31
0
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
    ''' Displays all the email for a given thread identifier '''
    store = get_store(request)
    thread = store.get_thread(mlist_fqdn, threadid)
    if not thread:
        raise Http404
    prev_thread, next_thread = store.get_thread_neighbors(mlist_fqdn, threadid)

    sort_mode = request.GET.get("sort", "thread")
    set_message_votes(thread.starting_email, request.user)

    # Tags
    tag_form = AddTagForm()
    try:
        tags = Tag.objects.filter(threadid=threadid, list_address=mlist_fqdn)
    except Tag.DoesNotExist:
        tags = []

    # Favorites
    fav_action = "add"
    if request.user.is_authenticated():
        try:
            Favorite.objects.get(list_address=mlist_fqdn,
                                 threadid=threadid,
                                 user=request.user)
        except Favorite.DoesNotExist:
            pass
        else:
            fav_action = "rm"

    # Category
    category, category_form = get_category_widget(request, thread.category)

    # Extract relative dates
    today = datetime.date.today()
    days_old = today - thread.starting_email.date.date()
    days_inactive = today - thread.last_email.date.date()

    mlist = store.get_list(mlist_fqdn)
    subject = stripped_subject(mlist, thread.starting_email.subject)

    # Last view
    last_view = None
    if request.user.is_authenticated():
        last_view_obj, created = LastView.objects.get_or_create(
            list_address=mlist_fqdn, threadid=threadid, user=request.user)
        if not created:
            last_view = last_view_obj.view_date
            last_view_obj.save()  # update timestamp
    # get the number of unread messages
    if last_view is None:
        if request.user.is_authenticated():
            unread_count = len(thread)
        else:
            unread_count = 0
    else:
        # XXX: Storm-specific
        unread_count = thread.replies_after(last_view).count()

    # Flash messages
    flash_messages = []
    flash_msg = request.GET.get("msg")
    if flash_msg:
        flash_msg = {
            "type": FLASH_MESSAGES[flash_msg][0],
            "msg": FLASH_MESSAGES[flash_msg][1]
        }
        flash_messages.append(flash_msg)

    # TODO: eventually move to a middleware ?
    # http://djangosnippets.org/snippets/1865/
    is_bot = True
    user_agent = request.META.get('HTTP_USER_AGENT', None)
    if user_agent:
        is_bot = robot_detection.is_robot(user_agent)

    context = {
        'mlist': mlist,
        'threadid': threadid,
        'subject': subject,
        'tags': tags,
        'addtag_form': tag_form,
        'month': thread.date_active,
        'first_mail': thread.starting_email,
        'neighbors': (prev_thread, next_thread),
        'months_list': get_months(store, mlist.name),
        'days_inactive': days_inactive.days,
        'days_old': days_old.days,
        'sort_mode': sort_mode,
        'fav_action': fav_action,
        'reply_form': ReplyForm(),
        'is_bot': is_bot,
        'num_comments': len(thread),
        'participants': thread.participants,
        'last_view': last_view,
        'unread_count': unread_count,
        'category_form': category_form,
        'category': category,
        'flash_messages': flash_messages,
    }
    context["participants"].sort(key=lambda x: x[0].lower())

    if is_bot:
        # Don't rely on AJAX to load the replies
        # The limit is a safety measure, don't let a bot kill the DB
        context["replies"] = _get_thread_replies(request, thread, limit=1000)

    return render(request, "thread.html", context)
Example #32
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')

    # Get stats for last 30 days
    today = datetime.datetime.utcnow()
    #today -= datetime.timedelta(days=365) #debug
    # the upper boundary is excluded in the search, add one day
    end_date = today + datetime.timedelta(days=1)
    begin_date = end_date - datetime.timedelta(days=32)

    store = get_store(request)
    mlist = store.get_list(mlist_fqdn)
    if mlist is None:
        raise Http404("No archived mailing-list by that name.")
    threads_result = store.get_threads(
            list_name=mlist.name, start=begin_date, end=end_date)

    threads = []
    participants = set()
    for thread_obj in threads_result:
        # Votes
        set_thread_votes(thread_obj, request.user)
        thread = Thread(thread_obj.thread_id, thread_obj.subject,
                        thread_obj.participants, len(thread_obj),
                        thread_obj.date_active.replace(tzinfo=utc),
                        thread_obj.likes, thread_obj.dislikes,
                        thread_obj.likestatus,
                        get_category_widget(None, thread_obj.category)[0],
                        is_thread_unread(request, mlist.name, thread_obj),
                        )
        # Statistics on how many participants and threads this month
        participants.update(thread.participants)
        threads.append(thread)

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: t.length, reverse=True)

    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if settings.USE_MOCKUPS:
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Top posters
    top_posters = []
    for poster in store.get_top_participants(list_name=mlist.name,
                start=begin_date, end=end_date, limit=5):
        top_posters.append({"name": poster[0], "email": poster[1],
                            "count": poster[2]})

    # Popular threads
    pop_threads = sorted([ t for t in threads if t.likes - t.dislikes > 0 ],
                         key=lambda t: t.likes - t.dislikes,
                         reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    # List activity
    # Use get_messages and not get_threads to count the emails, because
    # recently active threads include messages from before the start date
    emails_in_month = store.get_messages(list_name=mlist.name,
                                         start=begin_date, end=end_date)
    # graph
    dates = defaultdict(lambda: 0) # no activity by default
    # populate with all days before adding data.
    for single_date in daterange(begin_date, end_date):
        dates[single_date.strftime("%Y-%m-%d")] = 0

    for email in emails_in_month:
        date_str = email.date.strftime("%Y-%m-%d")
        dates[date_str] = dates[date_str] + 1
    days = dates.keys()
    days.sort()
    evolution = [dates[d] for d in days]
    if not evolution:
        evolution.append(0)
    archives_baseurl = reverse("archives_latest",
                               kwargs={'mlist_fqdn': mlist.name})
    archives_baseurl = archives_baseurl.rpartition("/")[0]

    context = {
        'view_name': 'overview',
        'mlist' : mlist,
        'top_threads': top_threads[:5],
        'most_active_threads': active_threads[:5],
        'top_author': authors,
        'top_posters': top_posters,
        'pop_threads': pop_threads[:5],
        'threads_by_category': threads_by_category,
        'months_list': get_months(store, mlist.name),
        'evolution': evolution,
        'days': days,
        'archives_baseurl': archives_baseurl,
        'num_threads': len(threads),
        'num_participants': len(participants),
    }
    return render(request, "overview.html", context)
Example #33
0
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
    ''' Displays all the email for a given thread identifier '''
    # pylint: disable=unused-argument
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    thread = get_object_or_404(Thread, mailinglist=mlist, thread_id=threadid)
    starting_email = thread.starting_email

    sort_mode = request.GET.get("sort", "thread")
    if request.user.is_authenticated():
        starting_email.myvote = starting_email.votes.filter(
            user=request.user).first()
    else:
        starting_email.myvote = None

    # Tags
    tag_form = AddTagForm()

    # Favorites
    fav_action = "add"
    if request.user.is_authenticated() and Favorite.objects.filter(
            thread=thread, user=request.user).exists():
        fav_action = "rm"

    # Category
    category, category_form = get_category_widget(request, thread.category)

    # Extract relative dates
    today = datetime.date.today()
    days_old = today - starting_email.date.date()
    days_inactive = today - thread.date_active.date()

    subject = stripped_subject(mlist, starting_email.subject)

    # Last view
    last_view = None
    if request.user.is_authenticated():
        last_view_obj, created = LastView.objects.get_or_create(
                thread=thread, user=request.user)
        if not created:
            last_view = last_view_obj.view_date
            last_view_obj.save() # update timestamp
    # get the number of unread messages
    if last_view is None:
        if request.user.is_authenticated():
            unread_count = thread.emails_count
        else:
            unread_count = 0
    else:
        unread_count = thread.emails.filter(date__gt=last_view).count()

    # TODO: eventually move to a middleware ?
    # http://djangosnippets.org/snippets/1865/
    user_agent = request.META.get('HTTP_USER_AGENT', None)
    if user_agent:
        is_bot = robot_detection.is_robot(user_agent)
    else:
        is_bot = True

    # Export button
    export = {
        "url": "%s?thread=%s" % (
            reverse("hk_list_export_mbox", kwargs={
                    "mlist_fqdn": mlist.name,
                    "filename": "%s-%s" % (mlist.name, thread.thread_id)}),
            thread.thread_id),
        "message": _("Download"),
        "title": _("This thread in gzipped mbox format"),
    }

    context = {
        'mlist': mlist,
        'thread': thread,
        'starting_email': starting_email,
        'subject': subject,
        'addtag_form': tag_form,
        'month': thread.date_active,
        'months_list': get_months(mlist),
        'days_inactive': days_inactive.days,
        'days_old': days_old.days,
        'sort_mode': sort_mode,
        'fav_action': fav_action,
        'reply_form': get_posting_form(ReplyForm, request, mlist),
        'is_bot': is_bot,
        'num_comments': thread.emails_count - 1,
        'last_view': last_view,
        'unread_count': unread_count,
        'category_form': category_form,
        'category': category,
        'export': export,
    }

    if is_bot:
        # Don't rely on AJAX to load the replies
        # The limit is a safety measure, don't let a bot kill the DB
        context["replies"] = _get_thread_replies(request, thread, limit=1000)

    return render(request, "hyperkitty/thread.html", context)
Example #34
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    threads = []
    for thread_obj in mlist.recent_threads:
        thread_obj.category_widget = get_category_widget(
                None, thread_obj.category)[0]
        threads.append(thread_obj)

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: t.emails_count, reverse=True)

    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if settings.USE_MOCKUPS:
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Popular threads
    pop_threads = []
    for t in threads:
        votes = t.get_votes()
        if votes["likes"] - votes["dislikes"] > 0:
            pop_threads.append(t)
    def _get_thread_vote_result(t):
        votes = t.get_votes()
        return votes["likes"] - votes["dislikes"]
    pop_threads.sort(key=_get_thread_vote_result, reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    # Personalized discussion groups: flagged/favorited threads and threads by user
    if request.user.is_authenticated():
        favorites = [ f.thread for f in Favorite.objects.filter(
            thread__mailinglist=mlist, user=request.user) ]
        mm_user_id = request.user.hyperkitty_profile.get_mailman_user_id()
        threads_posted_to = []
        if mm_user_id is not None:
            for thread in threads:
                senders = set([e.sender.mailman_id for e in thread.emails.all()])
                if mm_user_id in senders:
                    threads_posted_to.append(thread)
    else:
        favorites = []
        threads_posted_to = []

    # Empty messages # TODO: translate this
    empty_messages = {
        "flagged": 'You have not flagged any discussions (yet).',
        "posted": 'You have not posted to this list (yet).',
        "active": 'No discussions this month (yet).',
        "popular": 'No vote has been cast this month (yet).',
    }

    context = {
        'view_name': 'overview',
        'mlist' : mlist,
        'top_threads': top_threads[:20],
        'most_active_threads': active_threads[:20],
        'top_author': authors,
        'pop_threads': pop_threads[:20],
        'threads_by_category': threads_by_category,
        'months_list': get_months(mlist),
        'flagged_threads': favorites,
        'threads_posted_to': threads_posted_to,
        'empty_messages': empty_messages,
    }
    return render(request, "hyperkitty/overview.html", context)
Example #35
0
def overview(request, mlist_fqdn=None):
    if not mlist_fqdn:
        return redirect('/')
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    threads = mlist.recent_threads

    # top threads are the one with the most answers
    top_threads = sorted(threads, key=lambda t: t.emails_count, reverse=True)
    # active threads are the ones that have the most recent posting
    active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)

    # top authors are the ones that have the most kudos.  How do we determine
    # that?  Most likes for their post?
    if getattr(settings, 'USE_MOCKUPS', False):
        from hyperkitty.lib.mockup import generate_top_author
        authors = generate_top_author()
        authors = sorted(authors, key=lambda author: author.kudos)
        authors.reverse()
    else:
        authors = []

    # Popular threads
    pop_threads = []
    for t in threads:
        votes = t.get_votes()
        if votes["likes"] - votes["dislikes"] > 0:
            pop_threads.append(t)

    def _get_thread_vote_result(t):
        votes = t.get_votes()
        return votes["likes"] - votes["dislikes"]

    pop_threads.sort(key=_get_thread_vote_result, reverse=True)

    # Threads by category
    threads_by_category = {}
    for thread in active_threads:
        if not thread.category:
            continue
        # don't use defaultdict, use .setdefault():
        # http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
        if len(threads_by_category.setdefault(thread.category, [])) >= 5:
            continue
        threads_by_category[thread.category].append(thread)

    # Personalized discussion groups: flagged/favorited threads and threads by
    # user.
    if request.user.is_authenticated():
        favorites = [
            f.thread
            for f in Favorite.objects.filter(thread__mailinglist=mlist,
                                             user=request.user)
        ]
        mm_user_id = get_mailman_user_id(request.user)
        threads_posted_to = []
        if mm_user_id is not None:
            for thread in threads:
                senders = set(
                    [e.sender.mailman_id for e in thread.emails.all()])
                if mm_user_id in senders:
                    threads_posted_to.append(thread)
    else:
        favorites = []
        threads_posted_to = []

    # Empty messages # TODO: translate this
    empty_messages = {
        "flagged": 'You have not flagged any discussions (yet).',
        "posted": 'You have not posted to this list (yet).',
        "active": 'No discussions this month (yet).',
        "popular": 'No vote has been cast this month (yet).',
    }

    # Export button
    recent_dates = [d.strftime("%Y-%m-%d") for d in mlist.get_recent_dates()]
    recent_url = "%s?start=%s&end=%s" % (reverse(
        "hk_list_export_mbox",
        kwargs={
            "mlist_fqdn": mlist.name,
            "filename": "%s-%s-%s" %
            (mlist.name, recent_dates[0], recent_dates[1])
        }), recent_dates[0], recent_dates[1])
    today = datetime.date.today()
    month_dates = get_display_dates(today.year, today.month, None)
    month_url = "%s?start=%s&end=%s" % (reverse(
        "hk_list_export_mbox",
        kwargs={
            "mlist_fqdn": mlist.name,
            "filename": "%s-%s" % (mlist.name, today.strftime("%Y-%m"))
        }), month_dates[0].strftime("%Y-%m-%d"),
                                        month_dates[1].strftime("%Y-%m-%d"))
    export = {"recent": recent_url, "month": month_url}

    context = {
        'view_name': 'overview',
        'mlist': mlist,
        'top_threads': top_threads[:20],
        'most_active_threads': active_threads[:20],
        'top_author': authors,
        'pop_threads': pop_threads[:20],
        'threads_by_category': threads_by_category,
        'months_list': get_months(mlist),
        'flagged_threads': favorites,
        'threads_posted_to': threads_posted_to,
        'empty_messages': empty_messages,
        'export': export,
    }
    return render(request, "hyperkitty/overview.html", context)
Example #36
0
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            today = datetime.date.today()
            redirect_url = reverse('archives_with_month',
                                   kwargs={
                                       "mlist_fqdn": mlist_fqdn,
                                       'year': today.year,
                                       'month': today.month
                                   })
            redirect_url += "?msg=sent-ok"
            try:
                post_to_list(request,
                             mlist,
                             form.cleaned_data['subject'],
                             form.cleaned_data["message"],
                             attachments=request.FILES.getlist("attachment"))
            except PostingFailed, e:
                failure = str(e)
            else:
                return redirect(redirect_url)
    else:
        form = PostForm()
    context = {
        "mlist": mlist,
        "post_form": form,
        "failure": failure,
        'months_list': get_months(store, mlist.name),
    }
    return render(request, "message_new.html", context)
Example #37
0
    result = {"result": "Your reply has been sent and is being processed.", "message_html": html}
    if subscribed_now:
        result["result"] += "\n  You have been subscribed to {} list.".format(mlist_fqdn)
    return HttpResponse(json.dumps(result), content_type="application/javascript")


@login_required
@check_mlist_private
def new_message(request, mlist_fqdn):
    """ Sends a new thread-starting message to the list. """
    mlist = get_object_or_404(MailingList, name=mlist_fqdn)
    failure = None
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            today = datetime.date.today()
            redirect_url = reverse(
                "hk_archives_with_month", kwargs={"mlist_fqdn": mlist_fqdn, "year": today.year, "month": today.month}
            )
            redirect_url += "?msg=sent-ok"
            try:
                post_to_list(request, mlist, form.cleaned_data["subject"], form.cleaned_data["message"])
            except PostingFailed, e:
                failure = str(e)
            else:
                return redirect(redirect_url)
    else:
        form = PostForm()
    context = {"mlist": mlist, "post_form": form, "failure": failure, "months_list": get_months(mlist)}
    return render(request, "hyperkitty/message_new.html", context)