<commit_before># -*- coding: utf-8 -*-
"""
    Copyright 2013-2014 <NAME> <<EMAIL>>

    This file is part of the 1flow project.

    1flow is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    1flow is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public
    License along with 1flow.  If not, see http://www.gnu.org/licenses/

"""

import logging
import humanize

import gdata.gauth

from random import choice as random_choice
from constance import config
from mongoengine import Q

from django.http import (HttpResponseRedirect,
                         HttpResponsePermanentRedirect,
                         HttpResponseForbidden,
                         HttpResponseBadRequest,
                         HttpResponse)
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.contrib import messages
from django.shortcuts import render, redirect
from django.template import add_to_builtins
#from django.views.generic import ListView
from django.contrib.auth import authenticate, login, get_user_model
from django.utils.translation import (ugettext_lazy as _,
                                      ugettext as __, ungettext)

from django_select2.views import Select2View

#from infinite_pagination.paginator import InfinitePaginator
#from contact_importer.decorators import get_contacts
from endless_pagination.utils import get_page_number_from_request

from sparks.django.utils import HttpResponseTemporaryServerError

from .forms import (FullUserCreationForm,
                    UserProfileEditForm,
                    HomePreferencesForm,
                    ReadPreferencesForm,
                    SelectorPreferencesForm,
                    StaffPreferencesForm,
                    ManageFolderForm,
                    ManageSubscriptionForm,
                    AddSubscriptionForm,
                    WebPagesImportForm,
                    ReadShareForm)
from .tasks import import_google_reader_trigger
from .models.nonrel import (Feed, Subscription, FeedIsHtmlPageException,
                            Article, Read,
                            Folder, WebSite, Tag,
                            TreeCycleException,
                            CONTENT_TYPES_FINAL)
from .models.reldb import HelpContent
from ..base.utils import word_match_consecutive_once
from ..base.utils.dateutils import now

from .gr_import import GoogleReaderImport

LOGGER = logging.getLogger(__name__)
User = get_user_model()

# Avoid repetitive {% load … %} in templates.
add_to_builtins('django.templatetags.i18n')
add_to_builtins('django.templatetags.cache')
add_to_builtins('djangojs.templatetags.js')
add_to_builtins('pipeline.templatetags.compressed')
add_to_builtins('absolute.templatetags.absolute_future')
add_to_builtins('markdown_deux.templatetags.markdown_deux_tags')
add_to_builtins('widget_tweaks.templatetags.widget_tweaks')
add_to_builtins('endless_pagination.templatetags.endless')
add_to_builtins('oneflow.base.templatetags.base_utils')
add_to_builtins('oneflow.core.templatetags.coretags')

if settings.TEMPLATE_DEBUG:
    add_to_builtins('template_debug.templatetags.debug_tags')

# ———————————————————————————————————————————————————————————————————— Wrappers
# I couldn't find any way to create an URL patterns with a (?P<…>) that
# would be merged with a default `kwargs={…}` in the same URL pattern.
#
# Thus, these small view wrappers that just do the merge.
#


def read_feed_with_endless_pagination(request, **kwargs):

    kwargs.update({'is_read': False})  # , 'is_bookmarked': False})
    return read_with_endless_pagination(request, **kwargs)


def read_all_feed_with_endless_pagination(request, **kwargs):

    kwargs[u'all'] = True
    return read_with_endless_pagination(request, **kwargs)


def read_folder_with_endless_pagination(request, **kwargs):

    kwargs.update({'is_read': False})  # , 'is_bookmarked': False})
    return read_with_endless_pagination(request, **kwargs)


def read_all_folder_with_endless_pagination(request, **kwargs):

    kwargs[u'all'] = True
    return read_with_endless_pagination(request, **kwargs)


def make_read_wrapper(attrkey, typekey, view_name):
    """ See http://stackoverflow.com/a/3431699/654755 for why."""

    def func(request, **kwargs):
        kwargs[attrkey] = True
        return read_with_endless_pagination(request, **kwargs)

    final_func_name = 'read_{0}_{1}_with_endless_pagination'.format(view_name,
                                                                    typekey)

    #LOGGER.info(u'registered %s', final_func_name)

    globals()[final_func_name] = func


# This builds "read_later_feed_with_endless_pagination",
# 'read_later_folder_with_endless_pagination' and so on.

for attrkey, attrval in Read.status_data.items():
    if 'list_url' in attrval:
        # HEADS UP: sync the second argument with urls.py
        make_read_wrapper(attrkey, 'feed', attrval.get('view_name'))
        make_read_wrapper(attrkey, 'folder', attrval.get('view_name'))


# —————————————————————————————————————————————————————————————— Home / Sources


def skip_welcome_beta(request):

    user = request.user.mongo

    user.preferences.wizards.welcome_beta_shown = True
    user.preferences.save()

    # NOTE: The next 3 lines of code have to
    #       be synched with the home() view.

    if user.has_content:
        return redirect('source_selector')

    return redirect('add_subscription')


def home(request):
    """ root of the application. """

    user    = request.user.mongo
    wizards = user.preferences.wizards

    if wizards.welcome_beta_shown or not wizards.show_all:

        # NOTE: The next 3 lines of code have to be synched
        #       with the skip_welcome_beta() view.

        if user.has_content:
            return redirect('source_selector')

        return redirect('add_subscription')

    return render(request, 'home.html', {
        'gr_import': GoogleReaderImport(request.user.id),
    })


def source_selector(request, **kwargs):

    if request.is_ajax():
        template = u'snippets/selector/selector.html'

    else:
        template = u'selector.html'

    mongo_user     = request.user.mongo
    selector_prefs = mongo_user.preferences.selector

    return render(request, template, {
        'subscriptions':               mongo_user.subscriptions,
        'nofolder_open_subscriptions': mongo_user.nofolder_open_subscriptions,
        'closed_subscriptions':        mongo_user.nofolder_closed_subscriptions,
        'show_closed_streams':         selector_prefs.show_closed_streams,
        'titles_show_unread_count':    selector_prefs.titles_show_unread_count,
        'folders_show_unread_count':   selector_prefs.folders_show_unread_count,
    })


def manage_folder(request, **kwargs):
    """ This view does add/edit functions. """

    folder_id = kwargs.pop('folder', None)
    folder    = Folder.get_or_404(folder_id) if folder_id else None
    edit_mode = folder is not None
    user      = request.user.mongo

    if request.POST:
        messages.info(request, u'manage folder POST "%s"' % request.POST,
                      extra_tags='safe')

        if edit_mode:
            messages.info(request, u'manage folder EDIT %s' % folder,
                          extra_tags='safe')

            form = ManageFolderForm(request.POST, instance=folder,
                                    owner=user)

        else:
            form = ManageFolderForm(request.POST, owner=user)

        if form.is_valid():

            try:
                folder = form.save()

            except TreeCycleException, e:
                messages.error(request, _(u'Save <em>{0}</em> '
                               u'failed: {1}').format(folder.name, e),
                               extra_tags=u'safe')

            else:
                messages.info(request, _(u'Folder <em>{0}</em> successfully '
                              u'{1}.').format(folder.name, _(u'modified')
                                              if edit_mode else _(u'created')),
                              extra_tags=u'safe')

        else:
            messages.info(request, u'TEST2', extra_tags='safe')
            messages.warning(request, _(u'Could not {0} folder: {1}.').format(
                             _(u'modify') if edit_mode else _(u'create'),
                             form.errors), extra_tags='sticky safe')

            LOGGER.error(u'%s: %s', form.errors, form.cleaned_data)

        return HttpResponseRedirect(reverse('source_selector')
                                    + (u"#{0}".format(folder.id)
                                       if folder else u''))

    else:
        if not request.is_ajax():
            return HttpResponseBadRequest('Did you forget to do an Ajax call?')

        if folder:
            form = ManageFolderForm(instance=folder, owner=user)

        else:
            form = ManageFolderForm(owner=user)

    return render(request, 'snippets/selector/manage-folder.html',
                  {'form': form, 'folder': folder})


def delete_folder(request, folder):

    folder = Folder.get_or_404(folder)

    if request.user.is_superuser or folder.owner == request.user.mongo:
        folder.delete()
        return redirect('source_selector')

    return HttpResponseForbidden()


def edit_subscription(request, **kwargs):

    subscription_id = kwargs.pop('subscription', None)
    subscription    = Subscription.get_or_404(subscription_id)

    if request.POST:
        form = ManageSubscriptionForm(request.POST, instance=subscription)

        if form.is_valid():
            subscription = form.save()

            messages.info(request, _(u'Subscription <em>{0}</em> successfully '
                          u'modified.').format(subscription.name),
                          extra_tags='safe')

        else:
            messages.warning(request, _(u'Could not save '
                             u'subscription: {0}.').format(form.errors),
                             extra_tags='safe')

            LOGGER.error(form.errors)

        return HttpResponseRedirect(reverse('source_selector')
                                    + u"#{0}".format(subscription.id))

    else:
        if not request.is_ajax():
            return HttpResponseBadRequest('Did you forget to do an Ajax call?')

        form = ManageSubscriptionForm(instance=subscription)

    return render(request, 'snippets/selector/manage-subscription.html',
                  {'form': form, 'subscription': subscription})


def add_feed(request, feed_url, subscribe=True):
    """ The :param`subscribe` parameter is set to False for staff members
        who use a different URL. """

    user = request.user.mongo
    feeds = []
    feed = subscription = None
    feed_exc = sub_exc = None
    created = already_subscribed = False

    # Sanitize the URL as much as possible. Try to get the REFERER if the
    # user manually typed the address in the URL bar of his browser.
    try:
        if not feed_url.startswith(u'http'):
            if request.META.get('HTTP_REFERER', None):
                proto, host_and_port, remaining = WebSite.split_url(
                    request.META['HTTP_REFERER'])

                feed_url = u'{0}://{1}{2}{3}'.format(
                    proto, host_and_port,
                    u'' if feed_url.startswith(u'/') else u'/',
                    feed_url)

            else:
                LOGGER.error(u'Bad url {0} while trying to add a '
                             u'feed.'.format(feed_url))
                feed_exc = _(u'Malformed URL {0}').format(feed_url)

    except:
        LOGGER.exception(u'Very bad url {0} while trying to add a '
                         u'feed.'.format(feed_url))
        feed_exc = _(u'Very malformed url {0}').format(feed_url)

    if feed_exc is None:
        try:
            feeds = Feed.create_feeds_from_url(feed_url)

        except FeedIsHtmlPageException:
            feed_exc = _(u'The website at {0} does not seem '
                         u'to provide any feed.').format(feed_url)

        except Exception, e:
            feed_exc = _(u'Could not create any feed from '
                         u'URL {0}: {1}').format(feed_url, e)

    if feeds:
        # Taking the first is completely arbitrary, but better than nothing.
        # TODO: enhance this with a nice form to show all feeds to the user.
        feed, created = feeds[0]

        if subscribe:

            # Then subscribe the user to this feed,
            # and don't fail if he's already subscribed.
            try:
                subscription = Subscription.objects.get(user=user, feed=feed)

            except Subscription.DoesNotExist:
                try:
                    subscription = Subscription.subscribe_user_to_feed(
                        user, feed, background=True)

                except Exception, sub_exc:
                    LOGGER.exception(u'Failed to subscribe user %s to feed %s',
                                     user, feed)

            else:
                already_subscribed = True

    return render(request, 'add-feed.html', {
                  'feed': feed, 'created': created, 'feeds': feeds,
                  'subscription': subscription,<commit_msg>Implement #17.<commit_after># -*- coding: utf-8 -*-
"""
    Copyright 2013-2014 <NAME> <<EMAIL>>

    This file is part of the 1flow project.

    1flow is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    1flow is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public
    License along with 1flow.  If not, see http://www.gnu.org/licenses/

"""

import logging
import humanize

import gdata.gauth

from random import choice as random_choice
from constance import config
from mongoengine import Q

from django.http import (HttpResponseRedirect,
                         HttpResponsePermanentRedirect,
                         HttpResponseForbidden,
                         HttpResponseBadRequest,
                         HttpResponse)
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.contrib import messages
from django.shortcuts import render, redirect
from django.template import add_to_builtins
#from django.views.generic import ListView
from django.contrib.auth import authenticate, login, get_user_model
from django.utils.translation import (ugettext_lazy as _,
                                      ugettext as __, ungettext)

from django_select2.views import Select2View

#from infinite_pagination.paginator import InfinitePaginator
#from contact_importer.decorators import get_contacts
from endless_pagination.utils import get_page_number_from_request

from sparks.django.utils import HttpResponseTemporaryServerError

from .forms import (FullUserCreationForm,
                    UserProfileEditForm,
                    HomePreferencesForm,
                    ReadPreferencesForm,
                    SelectorPreferencesForm,
                    StaffPreferencesForm,
                    ManageFolderForm,
                    ManageSubscriptionForm,
                    AddSubscriptionForm,
                    WebPagesImportForm,
                    ReadShareForm)
from .tasks import import_google_reader_trigger
from .models.nonrel import (Feed, Subscription, FeedIsHtmlPageException,
                            Article, Read,
                            Folder, WebSite, Tag,
                            TreeCycleException,
                            CONTENT_TYPES_FINAL)
from .models.reldb import HelpContent
from ..base.utils import word_match_consecutive_once
from ..base.utils.dateutils import now

from .gr_import import GoogleReaderImport

LOGGER = logging.getLogger(__name__)
User = get_user_model()

# Avoid repetitive {% load … %} in templates.
add_to_builtins('django.templatetags.i18n')
add_to_builtins('django.templatetags.cache')
add_to_builtins('djangojs.templatetags.js')
add_to_builtins('pipeline.templatetags.compressed')
add_to_builtins('absolute.templatetags.absolute_future')
add_to_builtins('markdown_deux.templatetags.markdown_deux_tags')
add_to_builtins('widget_tweaks.templatetags.widget_tweaks')
add_to_builtins('endless_pagination.templatetags.endless')
add_to_builtins('oneflow.base.templatetags.base_utils')
add_to_builtins('oneflow.core.templatetags.coretags')

if settings.TEMPLATE_DEBUG:
    add_to_builtins('template_debug.templatetags.debug_tags')

# ———————————————————————————————————————————————————————————————————— Wrappers
# I couldn't find any way to create an URL patterns with a (?P<…>) that
# would be merged with a default `kwargs={…}` in the same URL pattern.
#
# Thus, these small view wrappers that just do the merge.
#


def read_feed_with_endless_pagination(request, **kwargs):

    kwargs.update({'is_read': False})  # , 'is_bookmarked': False})
    return read_with_endless_pagination(request, **kwargs)


def read_all_feed_with_endless_pagination(request, **kwargs):

    kwargs[u'all'] = True
    return read_with_endless_pagination(request, **kwargs)


def read_folder_with_endless_pagination(request, **kwargs):

    kwargs.update({'is_read': False})  # , 'is_bookmarked': False})
    return read_with_endless_pagination(request, **kwargs)


def read_all_folder_with_endless_pagination(request, **kwargs):

    kwargs[u'all'] = True
    return read_with_endless_pagination(request, **kwargs)


def make_read_wrapper(attrkey, typekey, view_name):
    """ See http://stackoverflow.com/a/3431699/654755 for why."""

    def func(request, **kwargs):
        kwargs[attrkey] = True
        return read_with_endless_pagination(request, **kwargs)

    final_func_name = 'read_{0}_{1}_with_endless_pagination'.format(view_name,
                                                                    typekey)

    #LOGGER.info(u'registered %s', final_func_name)

    globals()[final_func_name] = func


# This builds "read_later_feed_with_endless_pagination",
# 'read_later_folder_with_endless_pagination' and so on.

for attrkey, attrval in Read.status_data.items():
    if 'list_url' in attrval:
        # HEADS UP: sync the second argument with urls.py
        make_read_wrapper(attrkey, 'feed', attrval.get('view_name'))
        make_read_wrapper(attrkey, 'folder', attrval.get('view_name'))


# —————————————————————————————————————————————————————————————— Home / Sources


def skip_welcome_beta(request):

    user = request.user.mongo

    user.preferences.wizards.welcome_beta_shown = True
    user.preferences.save()

    # NOTE: The next 3 lines of code have to
    #       be synched with the home() view.

    if user.has_content:
        return redirect('source_selector')

    return redirect('add_subscription')


def home(request):
    """ root of the application. """

    user    = request.user.mongo
    wizards = user.preferences.wizards

    if wizards.welcome_beta_shown or not wizards.show_all:

        # NOTE: The next 3 lines of code have to be synched
        #       with the skip_welcome_beta() view.

        if user.has_content:
            return redirect('source_selector')

        return redirect('add_subscription')

    return render(request, 'home.html', {
        'gr_import': GoogleReaderImport(request.user.id),
    })


def source_selector(request, **kwargs):

    if request.is_ajax():
        template = u'snippets/selector/selector.html'

    else:
        template = u'selector.html'

    mongo_user     = request.user.mongo
    selector_prefs = mongo_user.preferences.selector

    return render(request, template, {
        'subscriptions':               mongo_user.subscriptions,
        'nofolder_open_subscriptions': mongo_user.nofolder_open_subscriptions,
        'closed_subscriptions':        mongo_user.nofolder_closed_subscriptions,
        'show_closed_streams':         selector_prefs.show_closed_streams,
        'titles_show_unread_count':    selector_prefs.titles_show_unread_count,
        'folders_show_unread_count':   selector_prefs.folders_show_unread_count,
    })


def manage_folder(request, **kwargs):
    """ This view does add/edit functions. """

    folder_id = kwargs.pop('folder', None)
    folder    = Folder.get_or_404(folder_id) if folder_id else None
    edit_mode = folder is not None
    user      = request.user.mongo

    if request.POST:
        messages.info(request, u'manage folder POST "%s"' % request.POST,
                      extra_tags='safe')

        if edit_mode:
            messages.info(request, u'manage folder EDIT %s' % folder,
                          extra_tags='safe')

            form = ManageFolderForm(request.POST, instance=folder,
                                    owner=user)

        else:
            form = ManageFolderForm(request.POST, owner=user)

        if form.is_valid():

            try:
                folder = form.save()

            except TreeCycleException, e:
                messages.error(request, _(u'Save <em>{0}</em> '
                               u'failed: {1}').format(folder.name, e),
                               extra_tags=u'safe')

            else:
                messages.info(request, _(u'Folder <em>{0}</em> successfully '
                              u'{1}.').format(folder.name, _(u'modified')
                                              if edit_mode else _(u'created')),
                              extra_tags=u'safe')

        else:
            messages.info(request, u'TEST2', extra_tags='safe')
            messages.warning(request, _(u'Could not {0} folder: {1}.').format(
                             _(u'modify') if edit_mode else _(u'create'),
                             form.errors), extra_tags='sticky safe')

            LOGGER.error(u'%s: %s', form.errors, form.cleaned_data)

        return HttpResponseRedirect(reverse('source_selector')
                                    + (u"#{0}".format(folder.id)
                                       if folder else u''))

    else:
        if not request.is_ajax():
            return HttpResponseBadRequest('Did you forget to do an Ajax call?')

        if folder:
            form = ManageFolderForm(instance=folder, owner=user)

        else:
            form = ManageFolderForm(owner=user)

    return render(request, 'snippets/selector/manage-folder.html',
                  {'form': form, 'folder': folder})


def delete_folder(request, folder):

    folder = Folder.get_or_404(folder)

    if request.user.is_superuser or folder.owner == request.user.mongo:
        folder.delete()
        return redirect('source_selector')

    return HttpResponseForbidden()


def edit_subscription(request, **kwargs):

    subscription_id = kwargs.pop('subscription', None)
    subscription    = Subscription.get_or_404(subscription_id)

    if request.POST:
        form = ManageSubscriptionForm(request.POST, instance=subscription)

        if form.is_valid():
            subscription = form.save()

            messages.info(request, _(u'Subscription <em>{0}</em> successfully '
                          u'modified.').format(subscription.name),
                          extra_tags='safe')

        else:
            messages.warning(request, _(u'Could not save '
                             u'subscription: {0}.').format(form.errors),
                             extra_tags='safe')

            LOGGER.error(form.errors)

        return HttpResponseRedirect(reverse('source_selector')
                                    + u"#{0}".format(subscription.id))

    else:
        if not request.is_ajax():
            return HttpResponseBadRequest('Did you forget to do an Ajax call?')

        form = ManageSubscriptionForm(instance=subscription)

    return render(request, 'snippets/selector/manage-subscription.html',
                  {'form': form, 'subscription': subscription})


def add_feed(request, feed_url, subscribe=True):
    """ Subscribe a user to a feed, given a feed URL.

        The :param`subscribe` parameter is set to ``False`` for staff
        members who use a different URL.
    """

    user = request.user.mongo
    feeds = []
    feed = subscription = None
    feed_exc = sub_exc = None
    created = already_subscribed = False

    # Sanitize the URL as much as possible. Try to get the REFERER if the
    # user manually typed the address in the URL bar of his browser.
    try:
        if not feed_url.startswith(u'http'):
            if request.META.get('HTTP_REFERER', None):
                proto, host_and_port, remaining = WebSite.split_url(
                    request.META['HTTP_REFERER'])

                feed_url = u'{0}://{1}{2}{3}'.format(
                    proto, host_and_port,
                    u'' if feed_url.startswith(u'/') else u'/',
                    feed_url)

            else:
                LOGGER.error(u'Bad url {0} while trying to add a '
                             u'feed.'.format(feed_url))
                feed_exc = _(u'Malformed URL {0}').format(feed_url)

    except:
        LOGGER.exception(u'Very bad url {0} while trying to add a '
                         u'feed.'.format(feed_url))
        feed_exc = _(u'Very malformed url {0}').format(feed_url)

    if feed_exc is None:
        try:
            feeds = Feed.create_feeds_from_url(feed_url)

        except FeedIsHtmlPageException:
            feed_exc = _(u'The website at {0} does not seem '
                         u'to provide any feed.').format(feed_url)

        except Exception, e:
            feed_exc = _(u'Could not create any feed from '
                         u'URL {0}: {1}').format(feed_url, e)

    if feeds:
        # Taking the first is completely arbitrary, but better than nothing.
        # TODO: enhance this with a nice form to show all feeds to the user.
        feed, created = feeds[0]

        if subscribe:

            # Then subscribe the user to this feed,
            # and don't fail if he's already subscribed.
            try:
                subscription = Subscription.objects.get(user=user, feed=feed)

            except Subscription.DoesNotExist:
                try:
                    subscription = Subscription.subscribe_user_to_feed(
                        user, feed, background=True)

                except Exception, sub_exc:
                    LOGGER.exception(u'Failed to subscribe user %s to feed %s',
                                     user, feed)

                else:
                    # A user subscribing to a feed from the web implicitely
                    # tells us that this feed is still running. Even if for
                    # some reason we closed it in the past, it seems OK now.
                    if feed.closed:
                        feed.reopen()

            else:
                already_subscribed = True

    return render(request, 'add-feed.html', {
                  'feed': feed, 'created': created, 'feeds': feeds,
                  'subscription': subscription,
{'fraction_non_alphanumeric': 0.09860672220626257, 'fraction_numerical': 0.004883654122378627, 'mean_word_length': 2.345627102354637, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5591972', 'n_tokens_mistral': 7981, 'n_tokens_neox': 7619, 'n_words': 1923}