<commit_before>import operator
from functools import reduce
from django.core.urlresolvers import reverse
from django.db.models import Count
from django.conf import settings
from django.utils.text import slugify
from django.utils.translation import ugettext as _
from django.views.generic import (CreateView, View, ListView, DetailView,
                                  UpdateView)
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db.models import Q
from qa.models import (UserQAProfile, Question, Answer, AnswerVote,
                       QuestionVote, AnswerComment, QuestionComment)
from .mixins import LoginRequired, AuthorRequiredMixin
from .utils import question_score
try:
    qa_messages = 'django.contrib.messages' in settings.INSTALLED_APPS and\
        settings.QA_MESSAGES
except AttributeError:
    qa_messages = False

if qa_messages:
    from django.contrib import messages

"""Dear maintainer:

Once you are done trying to 'optimize' this routine, and have realized what a
terrible mistake that was, please increment the following counter as a warning
to the next guy:

total_hours_wasted_here = 2
"""

class AnswerQuestionView(LoginRequired, View):
    """View to select an answer as the satisfying answer to the question and to
    mark the question as closed, validating than the user who created que
    question is the only one allowed to make those changes.
    """
    model = Answer

    def post(self, request, answer_id):
        answer = get_object_or_404(self.model, pk=answer_id)
        if answer.question.user != request.user:
            raise ValidationError(
                "Sorry, you're not allowed to close this question.")
        else:
            answer.question.closed = True
            answer.question.save()
            answer.answer = True
            answer.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)

        else:
            return redirect(reverse('qa_index'))

class QuestionIndexView(ListView):
    """CBV to render the index view
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'
    ordering = '-pub_date'

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionIndexView, self).get_context_data(*args, **kwargs)
        noans = Question.objects.order_by('-pub_date').filter(
            answer__isnull=True)[:10].select_related('user')\
            .annotate(num_answers=Count('answer', distinct=True),
                      num_question_comments=Count('questioncomment',
                      distinct=True))
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = noans
        context['reward'] = Question.objects.order_by('-reward').filter(
            reward__gte=1)[:10]
        return context

    def get_queryset(self):
        queryset = super(QuestionIndexView, self).get_queryset()\
            .select_related('user')\
            .annotate(num_answers=Count('answer', distinct=True),
                      num_question_comments=Count('questioncomment',
                      distinct=True))
        return queryset

class QuestionsSearchView(QuestionIndexView):
    """
    Display a ListView page inherithed from the QuestionIndexView filtered by
    the search query and sorted by the different elements aggregated.
    """

    def get_queryset(self):
        result = super(QuestionsSearchView, self).get_queryset()
        query = self.request.GET.get('word')
        if query:
            query_list = query.split()
            result = result.filter(
                reduce(operator.and_,
                       (Q(title__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(description__icontains=q) for q in query_list))
            )

        return result

        def get_context_data(self, *args, **kwargs):
            context = super(
                QuestionsSearchView, self).get_context_data(*args, **kwargs)
            context['totalcount'] = Question.objects.count
            context['anscount'] = Answer.objects.count
            context['noans'] = Question.objects.order_by('-pub_date').filter(
                answer__isnull=True)[:10]
            context['reward'] = Question.objects.order_by('-reward').filter(
                reward__gte=1)[:10]
            return context

class QuestionsByTagView(ListView):
    """View to call all the questions clasiffied under one specific tag.
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'

    def get_queryset(self, **kwargs):
        return Question.objects.filter(tags__slug=self.kwargs['tag'])

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionsByTagView, self).get_context_data(*args, **kwargs)
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = Question.objects.order_by('-pub_date').filter(
            tags__name__contains=self.kwargs['tag'], answer__isnull=True)[:10]
        context['reward'] = Question.objects.order_by('-reward').filter(
            tags__name__contains=self.kwargs['tag'],
            reward__gte=1)[:10]
        return context

class CreateQuestionView(LoginRequired, CreateView):
    """
    View to handle the creation of a new question
    """
    template_name = 'qa/create_question.html'
    model = Question
    fields = ['title', 'description', 'tags']
    message = _('Thank you! your question has been created.')

    def form_valid(self, form):
        """
        Create the required relation
        """
        form.instance.user = self.request.user
        return super(CreateQuestionView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_index')

class UpdateQuestionView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question
    """
    template_name = 'qa/update_question.html'
    model = Question
    pk_url_kwarg = 'question_id'
    fields = ['title', 'description', 'tags']

    def get_success_url(self):
        question = self.get_object()
        return reverse('qa_detail', kwargs={'pk': question.pk})

class CreateAnswerView(LoginRequired, CreateView):
    """
    View to create new answers for a given question
    """
    template_name = 'qa/create_answer.html'
    model = Answer
    fields = ['answer_text']
    message = _('Thank you! your answer has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/question
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateAnswerView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateAnswerView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question answer
    """
    template_name = 'qa/update_answer.html'
    model = Answer
    pk_url_kwarg = 'answer_id'
    fields = ['answer_text']

    def get_success_url(self):
        answer = self.get_object()
        return reverse('qa_detail', kwargs={'pk': answer.question.pk})

class CreateAnswerCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given answer
    """
    template_name = 'qa/create_comment.html'
    model = AnswerComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.answer_id = self.kwargs['answer_id']
        return super(CreateAnswerCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        question_pk = Answer.objects.get(
            id=self.kwargs['answer_id']).question.pk
        return reverse('qa_detail', kwargs={'pk': question_pk})

class CreateQuestionCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between question
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateQuestionCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateQuestionCommentView(LoginRequired,
                                AuthorRequiredMixin, UpdateView):
    """
    Updates the comment question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    pk_url_kwarg = 'comment_id'
    fields = ['comment_text']

    def get_success_url(self):
        question_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': question_comment.question.pk})

class UpdateAnswerCommentView(UpdateQuestionCommentView):
    """
    Updates the comment answer
    """
    model = AnswerComment

    def get_success_url(self):
        answer_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': answer_comment.answer.question.pk})

class QuestionDetailView(DetailView):
    """
    View to call a question and to render all the details about that question.
    """
    model = Question
    template_name = 'qa/detail_question.html'
    context_object_name = 'question'

    def get_context_data(self, **kwargs):
        answers = self.object.answer_set.all().order_by('pub_date')
        context = super(QuestionDetailView, self).get_context_data(**kwargs)
        context['last_comments'] = self.object.questioncomment_set.order_by(
            'pub_date')[:5]
        context['answers'] = answers.select_related('user')
        return context

    def get(self, request, **kwargs):
        my_object = self.get_object()
        slug = kwargs.get('slug', '')
        if slug != slugify(my_object.title):
            kwargs['slug'] = slugify(my_object.title)
            return redirect(reverse('qa_detail', kwargs=kwargs))
        else:
            my_object.views += 1
            my_object.save()
            return super(QuestionDetailView, self).get(request, **kwargs)

    def get_object(self):
        # Call the superclass
        question = super(QuestionDetailView, self).get_object()
        return question

class ParentVoteView(View):
    """
    Base class to create a vote for a given model (question/answer)
    """
    model = None
    vote_model = None

    def get_vote_kwargs(self, user, vote_target):
        """
        This takes the user and the vote and adjusts the kwargs
        depending on the used model.
        """
        object_kwargs = {'user': user}
        if self.model == Question:
            target_key = 'question'
        elif self.model == Answer:
            target_key = 'answer'
        else:
            raise ValidationError('Not a valid model for votes')
        object_kwargs[target_key] = vote_target
        return object_kwargs

    def post(self, request, object_id):
        vote_target = get_object_or_404(self.model, pk=object_id)
        if vote_target.user == request.user:
            raise ValidationError(
                'Sorry, voting for your own answer is not possible.')
        else:
            upvote = request.POST.get('upvote', None) is not None
            object_kwargs = self.get_vote_kwargs(request.user, vote_target)
            vote, created = self.vote_model.objects.get_or_create(
                defaults={'value': upvote},
                **object_kwargs)
            if created:
                vote_target.user.userqaprofile.points += 1 if upvote else -1
                if upvote:
                    vote_target.positive_votes += 1
                else:
                    vote_target.negative_votes += 1
            else:
                if vote.value == upvote:
                    vote.delete()
                    vote_target.user.userqaprofile.points += -1 if upvote else 1
                    if upvote:
                        vote_target.positive_votes -= 1
                    else:
                        vote_target.negative_votes -= 1
                else:
                    vote_target.user.userqaprofile.points += 2 if upvote else -2
                    vote.value = upvote
                    vote.save()
                    if upvote:
                        vote_target.positive_votes += 1
                        vote_target.negative_votes -= 1
                    else:
                        vote_target.negative_votes += 1
                        vote_target.positive_votes -= 1

            vote_target.user.userqaprofile.save()
            if self.model == Question:
                vote_target.reward = question_score(vote_target)
            if self.model == Answer:
                vote_target.question.reward = question_score(
                    vote_target.question)
                vote_target.question.save()
            vote_target.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)
        else:
            return redirect(reverse('qa_index'))

class AnswerVoteView(ParentVoteView):
    """
    Class to upvote answers
    """
    model = Answer
    vote_model = AnswerVote

class QuestionVoteView(ParentVoteView):
    """
    Class to upvote questions
    """
    model = Question
    vote_model = QuestionVote

def profile(request, user_id):
    user_ob = get_user_model().objects.get(id=user_id)
    user = UserQAProfile.objects.get(user=user_ob)
    return render(request, 'qa/profile.html', {'user': user})
<commit_msg>Minor changes to reduce queries<commit_after>import operator
from functools import reduce
from django.core.urlresolvers import reverse
from django.db.models import Count
from django.conf import settings
from django.utils.text import slugify
from django.utils.translation import ugettext as _
from django.views.generic import (CreateView, View, ListView, DetailView,
                                  UpdateView)
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db.models import Q
from qa.models import (UserQAProfile, Question, Answer, AnswerVote,
                       QuestionVote, AnswerComment, QuestionComment)
from .mixins import LoginRequired, AuthorRequiredMixin
from .utils import question_score
try:
    qa_messages = 'django.contrib.messages' in settings.INSTALLED_APPS and\
        settings.QA_MESSAGES
except AttributeError:
    qa_messages = False

if qa_messages:
    from django.contrib import messages

"""Dear maintainer:

Once you are done trying to 'optimize' this routine, and have realized what a
terrible mistake that was, please increment the following counter as a warning
to the next guy:

total_hours_wasted_here = 2
"""

class AnswerQuestionView(LoginRequired, View):
    """View to select an answer as the satisfying answer to the question and to
    mark the question as closed, validating than the user who created que
    question is the only one allowed to make those changes.
    """
    model = Answer

    def post(self, request, answer_id):
        answer = get_object_or_404(self.model, pk=answer_id)
        if answer.question.user != request.user:
            raise ValidationError(
                "Sorry, you're not allowed to close this question.")
        else:
            answer.question.closed = True
            answer.question.save()
            answer.answer = True
            answer.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)

        else:
            return redirect(reverse('qa_index'))

class QuestionIndexView(ListView):
    """CBV to render the index view
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'
    ordering = '-pub_date'

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionIndexView, self).get_context_data(*args, **kwargs)
        noans = Question.objects.order_by('-pub_date').filter(
            answer__isnull=True)[:10].select_related('user')\
            .annotate(num_answers=Count('answer', distinct=True),
                      num_question_comments=Count('questioncomment',
                      distinct=True))
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = noans
        context['reward'] = Question.objects.order_by('-reward').filter(
            reward__gte=1)[:10]
        return context

    def get_queryset(self):
        queryset = super(QuestionIndexView, self).get_queryset()\
            .select_related('user')\
            .annotate(num_answers=Count('answer', distinct=True),
                      num_question_comments=Count('questioncomment',
                      distinct=True))
        return queryset

class QuestionsSearchView(QuestionIndexView):
    """
    Display a ListView page inherithed from the QuestionIndexView filtered by
    the search query and sorted by the different elements aggregated.
    """

    def get_queryset(self):
        result = super(QuestionsSearchView, self).get_queryset()
        query = self.request.GET.get('word')
        if query:
            query_list = query.split()
            result = result.filter(
                reduce(operator.and_,
                       (Q(title__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(description__icontains=q) for q in query_list))
            )

        return result

        def get_context_data(self, *args, **kwargs):
            context = super(
                QuestionsSearchView, self).get_context_data(*args, **kwargs)
            context['totalcount'] = Question.objects.count
            context['anscount'] = Answer.objects.count
            context['noans'] = Question.objects.order_by('-pub_date').filter(
                answer__isnull=True)[:10]
            context['reward'] = Question.objects.order_by('-reward').filter(
                reward__gte=1)[:10]
            return context

class QuestionsByTagView(ListView):
    """View to call all the questions clasiffied under one specific tag.
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'

    def get_queryset(self, **kwargs):
        return Question.objects.filter(tags__slug=self.kwargs['tag'])

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionsByTagView, self).get_context_data(*args, **kwargs)
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = Question.objects.order_by('-pub_date').filter(
            tags__name__contains=self.kwargs['tag'], answer__isnull=True)[:10]
        context['reward'] = Question.objects.order_by('-reward').filter(
            tags__name__contains=self.kwargs['tag'],
            reward__gte=1)[:10]
        return context

class CreateQuestionView(LoginRequired, CreateView):
    """
    View to handle the creation of a new question
    """
    template_name = 'qa/create_question.html'
    model = Question
    fields = ['title', 'description', 'tags']
    message = _('Thank you! your question has been created.')

    def form_valid(self, form):
        """
        Create the required relation
        """
        form.instance.user = self.request.user
        return super(CreateQuestionView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_index')

class UpdateQuestionView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question
    """
    template_name = 'qa/update_question.html'
    model = Question
    pk_url_kwarg = 'question_id'
    fields = ['title', 'description', 'tags']

    def get_success_url(self):
        question = self.get_object()
        return reverse('qa_detail', kwargs={'pk': question.pk})

class CreateAnswerView(LoginRequired, CreateView):
    """
    View to create new answers for a given question
    """
    template_name = 'qa/create_answer.html'
    model = Answer
    fields = ['answer_text']
    message = _('Thank you! your answer has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/question
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateAnswerView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateAnswerView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question answer
    """
    template_name = 'qa/update_answer.html'
    model = Answer
    pk_url_kwarg = 'answer_id'
    fields = ['answer_text']

    def get_success_url(self):
        answer = self.get_object()
        return reverse('qa_detail', kwargs={'pk': answer.question.pk})

class CreateAnswerCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given answer
    """
    template_name = 'qa/create_comment.html'
    model = AnswerComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.answer_id = self.kwargs['answer_id']
        return super(CreateAnswerCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        question_pk = Answer.objects.get(
            id=self.kwargs['answer_id']).question.pk
        return reverse('qa_detail', kwargs={'pk': question_pk})

class CreateQuestionCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between question
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateQuestionCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateQuestionCommentView(LoginRequired,
                                AuthorRequiredMixin, UpdateView):
    """
    Updates the comment question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    pk_url_kwarg = 'comment_id'
    fields = ['comment_text']

    def get_success_url(self):
        question_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': question_comment.question.pk})

class UpdateAnswerCommentView(UpdateQuestionCommentView):
    """
    Updates the comment answer
    """
    model = AnswerComment

    def get_success_url(self):
        answer_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': answer_comment.answer.question.pk})

class QuestionDetailView(DetailView):
    """
    View to call a question and to render all the details about that question.
    """
    model = Question
    template_name = 'qa/detail_question.html'
    context_object_name = 'question'

    def get_context_data(self, **kwargs):
        answers = self.object.answer_set.all().order_by('pub_date')
        context = super(QuestionDetailView, self).get_context_data(**kwargs)
        context['last_comments'] = self.object.questioncomment_set.order_by(
            'pub_date')[:5]
        context['answers'] = list(answers.select_related('user')\
            .select_related('user__userqaprofile')\
            .annotate(answercomment_count=Count('answercomment')))
        return context

    def get(self, request, **kwargs):
        my_object = self.get_object()
        slug = kwargs.get('slug', '')
        if slug != slugify(my_object.title):
            kwargs['slug'] = slugify(my_object.title)
            return redirect(reverse('qa_detail', kwargs=kwargs))
        else:
            my_object.views += 1
            my_object.save()
            return super(QuestionDetailView, self).get(request, **kwargs)

    def get_object(self):
        # Call the superclass
        question = super(QuestionDetailView, self).get_object()
        return question

class ParentVoteView(View):
    """
    Base class to create a vote for a given model (question/answer)
    """
    model = None
    vote_model = None

    def get_vote_kwargs(self, user, vote_target):
        """
        This takes the user and the vote and adjusts the kwargs
        depending on the used model.
        """
        object_kwargs = {'user': user}
        if self.model == Question:
            target_key = 'question'
        elif self.model == Answer:
            target_key = 'answer'
        else:
            raise ValidationError('Not a valid model for votes')
        object_kwargs[target_key] = vote_target
        return object_kwargs

    def post(self, request, object_id):
        vote_target = get_object_or_404(self.model, pk=object_id)
        if vote_target.user == request.user:
            raise ValidationError(
                'Sorry, voting for your own answer is not possible.')
        else:
            upvote = request.POST.get('upvote', None) is not None
            object_kwargs = self.get_vote_kwargs(request.user, vote_target)
            vote, created = self.vote_model.objects.get_or_create(
                defaults={'value': upvote},
                **object_kwargs)
            if created:
                vote_target.user.userqaprofile.points += 1 if upvote else -1
                if upvote:
                    vote_target.positive_votes += 1
                else:
                    vote_target.negative_votes += 1
            else:
                if vote.value == upvote:
                    vote.delete()
                    vote_target.user.userqaprofile.points += -1 if upvote else 1
                    if upvote:
                        vote_target.positive_votes -= 1
                    else:
                        vote_target.negative_votes -= 1
                else:
                    vote_target.user.userqaprofile.points += 2 if upvote else -2
                    vote.value = upvote
                    vote.save()
                    if upvote:
                        vote_target.positive_votes += 1
                        vote_target.negative_votes -= 1
                    else:
                        vote_target.negative_votes += 1
                        vote_target.positive_votes -= 1

            vote_target.user.userqaprofile.save()
            if self.model == Question:
                vote_target.reward = question_score(vote_target)
            if self.model == Answer:
                vote_target.question.reward = question_score(
                    vote_target.question)
                vote_target.question.save()
            vote_target.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)
        else:
            return redirect(reverse('qa_index'))

class AnswerVoteView(ParentVoteView):
    """
    Class to upvote answers
    """
    model = Answer
    vote_model = AnswerVote

class QuestionVoteView(ParentVoteView):
    """
    Class to upvote questions
    """
    model = Question
    vote_model = QuestionVote

def profile(request, user_id):
    user_ob = get_user_model().objects.get(id=user_id)
    user = UserQAProfile.objects.get(user=user_ob)
    return render(request, 'qa/profile.html', {'user': user})
<|endoftext|>


<commit_before>from PIL import Image
import os, sys, argparse

# best down-sizing filter ANTIALIAS
def Resize(image, path, w, h, mode = Image.ANTIALIAS):
	path = os.path.abspath(os.path.expanduser(path))
	dir = os.path.dirname(path)
	if not os.path.isdir(dir):
		os.makedirs(dir)
	newimage = image.resize((w, h), mode)
	newimage.save(path)
pass

def MakeAndroidIcon(iconFile):
	im = Image.open(iconFile)
	Resize(im, "res/drawable-ldpi/app_icon.png", 36, 36)
	Resize(im, "res/drawable/app_icon.png", 48, 48)
	Resize(im, "res/drawable-hdpi/app_icon.png", 72, 72)
	Resize(im, "res/drawable-xhdpi/app_icon.png", 96, 96)
	Resize(im, "res/drawable-xxhdpi/app_icon.png", 144, 144)
	Resize(im, "res/drawable-xxxhdpi/app_icon.png", 192, 192)
pass

def MakeiOSIcon(iconFile):
	im = Image.open(iconFile)
	Resize(im, "AppIcon.appiconset/Icon.png", 57, 57)
	Resize(im, "AppIcon.appiconset/Icon@2x.png", 114, 114)
	Resize(im, "AppIcon.appiconset/Icon-72.png", 72, 72)
	Resize(im, "AppIcon.appiconset/Icon-76.png", 76, 76)
	Resize(im, "AppIcon.appiconset/Icon-120.png", 120, 120)
	Resize(im, "AppIcon.appiconset/Icon-144.png", 144, 144)
	Resize(im, "AppIcon.appiconset/Icon-152.png", 152, 152)
	Resize(im, "AppIcon.appiconset/Icon-180.png", 180, 180)
pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description = 'icon image scaler')
    parser.add_argument('iconFile', help = 'origin icon image file')
    parser.add_argument('-android', action = 'store_true', help = 'make android icon image set')
    parser.add_argument('-ios', action = 'store_true', help = 'make ios icon image set')
    args = parser.parse_args()
    if os.path.isfile(args.iconFile):
        iconFile = os.path.abspath(args.iconFile)
        if args.android:
            MakeAndroidIcon(iconFile)
        if args.ios:
            MakeiOSIcon(iconFile)
    else:
        print('origin icon image file not exist')
    pass
<commit_msg>add #!usr/bin/python<commit_after>#!/usr/bin/python
from PIL import Image
import os, sys, argparse

# best down-sizing filter ANTIALIAS
def Resize(image, path, w, h, mode = Image.ANTIALIAS):
	path = os.path.abspath(os.path.expanduser(path))
	dir = os.path.dirname(path)
	if not os.path.isdir(dir):
		os.makedirs(dir)
	newimage = image.resize((w, h), mode)
	newimage.save(path)
pass

def MakeAndroidIcon(iconFile):
	im = Image.open(iconFile)
	Resize(im, "res/drawable-ldpi/app_icon.png", 36, 36)
	Resize(im, "res/drawable/app_icon.png", 48, 48)
	Resize(im, "res/drawable-hdpi/app_icon.png", 72, 72)
	Resize(im, "res/drawable-xhdpi/app_icon.png", 96, 96)
	Resize(im, "res/drawable-xxhdpi/app_icon.png", 144, 144)
	Resize(im, "res/drawable-xxxhdpi/app_icon.png", 192, 192)
pass

def MakeiOSIcon(iconFile):
	im = Image.open(iconFile)
	Resize(im, "AppIcon.appiconset/Icon.png", 57, 57)
	Resize(im, "AppIcon.appiconset/Icon@2x.png", 114, 114)
	Resize(im, "AppIcon.appiconset/Icon-72.png", 72, 72)
	Resize(im, "AppIcon.appiconset/Icon-76.png", 76, 76)
	Resize(im, "AppIcon.appiconset/Icon-120.png", 120, 120)
	Resize(im, "AppIcon.appiconset/Icon-144.png", 144, 144)
	Resize(im, "AppIcon.appiconset/Icon-152.png", 152, 152)
	Resize(im, "AppIcon.appiconset/Icon-180.png", 180, 180)
pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description = 'icon image scaler')
    parser.add_argument('iconFile', help = 'origin icon image file')
    parser.add_argument('-android', action = 'store_true', help = 'make android icon image set')
    parser.add_argument('-ios', action = 'store_true', help = 'make ios icon image set')
    args = parser.parse_args()
    if os.path.isfile(args.iconFile):
        iconFile = os.path.abspath(args.iconFile)
        if args.android:
            MakeAndroidIcon(iconFile)
        if args.ios:
            MakeiOSIcon(iconFile)
    else:
        print('origin icon image file not exist')
    pass
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# Copyright (c) 2012, Roberto Riggio
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#    * Neither the name of the CREATE-NET nor the
#      names of its contributors may be used to endorse or promote products
#      derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY CREATE-NET ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL CREATE-NET BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""
A command line utility for interfacing with the energino power
consumption monitor.
"""

import optparse
import logging
import sys
import serial
import glob
import math
import time
import datetime

DEFAULT_PORT = '/dev/ttyACM0'
DEFAULT_PORT_SPEED = 115200
DEFAULT_INTERVAL = 2000
LOG_FORMAT = '%(asctime)-15s %(message)s'

def unpack_energino_v1(line):
    logging.debug("line: %s" % line.replace('\n',''))
    if type(line) is str and len(line) > 0 and line[0] == "#" and line[-1] == '\n':
        readings = line[1:-1].split(",")
        if len(readings) == 14:
            return { 'voltage' : float(readings[2]),
                'current' : float(readings[3]),
                'power' : float(readings[4]),
                'switch' : int(readings[5]),
                'window' : int(readings[6]),
                'samples' : int(readings[7]),
                'ip' : readings[8],
                'server_port' : readings[9],
                'host' : readings[10],
                'host_port' : readings[11],
                'feed' : readings[12],
                'key' : readings[13]}
    raise Exception, "invalid line: %s" % line[0:-1]

MODELS = { "Energino" : { 1 : unpack_energino_v1 } }

class PyEnergino(object):

    def __init__(self, port=DEFAULT_PORT, bps=DEFAULT_PORT_SPEED, interval = DEFAULT_INTERVAL):
        self.interval = interval
        self.ser = serial.Serial(baudrate=bps, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS)
        devs = glob.glob(port + "*")
        for dev in devs:
            logging.debug("scanning %s" % dev)
            self.ser.port = dev
            self.ser.open()
            time.sleep(2)
            try:
                self.configure()
            except:
                try:
                    self.configure()
                except:
                    self.configure()
            self.send_cmds([ "#P%u" % self.interval ])
            try:
                self.unpack(self.ser.readline())
            except:
                try:
                    self.unpack(self.ser.readline())
                except:
                    self.unpack(self.ser.readline())

            logging.debug("attaching to port %s!" % dev)
            return
        raise Exception, "unable to configure serial port"

    def send_cmd(self, cmd):
        logging.debug("sending initialization sequence %s" % cmd)
        self.write(cmd + '\n')
        time.sleep(2)
        self.unpack(self.ser.readline())

    def send_cmds(self, cmds):
        for cmd in cmds:
            self.send_cmd(cmd)

    def configure(self):
        line = self.ser.readline()
        logging.debug("line: %s" % line.replace('\n',''))
        if type(line) is str and len(line) > 0 and line[0] == "#" and line[-1] == '\n':
            readings = line[1:-1].split(",")
            if readings[0] in MODELS.keys():
                logging.debug("found %s version %u" % (readings[0], int(readings[1])))
                self.unpack = MODELS[readings[0]][int(readings[1])]
                return
        raise Exception, "unable to identify model: %s" % line

    def write(self, value):
        self.ser.flushOutput()
        self.ser.write(value)

    def fetch(self):
        readings = self.unpack(self.ser.readline())
        readings['port'] = self.ser.port
        readings['at'] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ")
        delta = math.fabs(self.interval - readings['window'])
        if delta / self.interval > 0.1:
            logging.debug("polling drift is higher than 10%%, target is %u actual is %u" % (self.interval, readings['window']))
        return readings

def main():

    p = optparse.OptionParser()
    p.add_option('--port', '-p', dest="port", default=DEFAULT_PORT)
    p.add_option('--interval', '-i', dest="interval", default=DEFAULT_INTERVAL)
    p.add_option('--offset', '-o', dest="offset", default=None)
    p.add_option('--sensitivity', '-s', dest="sensitivity", default=None)
    p.add_option('--bps', '-b', dest="bps", default=DEFAULT_PORT_SPEED)
    p.add_option('--verbose', '-v', action="store_true", dest="verbose", default=False)
    p.add_option('--log', '-l', dest="log")
    options, _ = p.parse_args()
    init = []
    if options.offset != None:
        init.append("#C%s" % options.offset)
    if options.sensitivity != None:
        init.append("#D%s" % options.sensitivity)
    if options.verbose:
        lvl = logging.DEBUG
    else:
        lvl = logging.INFO
    logging.basicConfig(level=lvl, format=LOG_FORMAT, filename=options.log, filemode='w')
    energino = PyEnergino(options.port, options.bps, int(options.interval))
    energino.send_cmds(init)
    while True:
        energino.ser.flushInput()
        try:
            readings = energino.fetch()
        except KeyboardInterrupt:
            logging.debug("Bye!")
            sys.exit()
        except:
            logging.debug("0 [V] 0 [A] 0 [W] 0 [samples] 0 [window]")
        else:
            logging.info("%s [V] %s [A] %s [W] %s [samples] %s [window]" % (readings['voltage'], readings['current'], readings['power'], readings['samples'], readings['window']))

if __name__ == "__main__":
    main()
    <commit_msg>Try three time to configure the serial port, then give up and raise exeception.<commit_after>#!/usr/bin/env python
#
# Copyright (c) 2012, Roberto Riggio
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#    * Neither the name of the CREATE-NET nor the
#      names of its contributors may be used to endorse or promote products
#      derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY CREATE-NET ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL CREATE-NET BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""
A command line utility for interfacing with the energino power
consumption monitor.
"""

import optparse
import logging
import sys
import serial
import glob
import math
import time
import datetime

DEFAULT_PORT = '/dev/ttyACM0'
DEFAULT_PORT_SPEED = 115200
DEFAULT_INTERVAL = 2000
LOG_FORMAT = '%(asctime)-15s %(message)s'

def unpack_energino_v1(line):
    logging.debug("line: %s" % line.replace('\n',''))
    if type(line) is str and len(line) > 0 and line[0] == "#" and line[-1] == '\n':
        readings = line[1:-1].split(",")
        if len(readings) == 14:
            return { 'voltage' : float(readings[2]),
                'current' : float(readings[3]),
                'power' : float(readings[4]),
                'switch' : int(readings[5]),
                'window' : int(readings[6]),
                'samples' : int(readings[7]),
                'ip' : readings[8],
                'server_port' : readings[9],
                'host' : readings[10],
                'host_port' : readings[11],
                'feed' : readings[12],
                'key' : readings[13]}
    raise Exception, "invalid line: %s" % line[0:-1]

MODELS = { "Energino" : { 1 : unpack_energino_v1 } }

class PyEnergino(object):

    def __init__(self, port=DEFAULT_PORT, bps=DEFAULT_PORT_SPEED, interval = DEFAULT_INTERVAL):
        self.interval = interval
        self.ser = serial.Serial(baudrate=bps, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS)
        devs = glob.glob(port + "*")
        for dev in devs:
            logging.debug("scanning %s" % dev)
            self.ser.port = dev
            self.ser.open()
            time.sleep(2)
            self.configure()
            logging.debug("attaching to port %s!" % dev)
            return
        raise Exception, "unable to configure serial port"

    def send_cmd(self, cmd):
        logging.debug("sending initialization sequence %s" % cmd)
        self.write(cmd + '\n')
        time.sleep(2)
        self.unpack(self.ser.readline())

    def send_cmds(self, cmds):
        for cmd in cmds:
            self.send_cmd(cmd)

    def configure(self):
        for _ in range(0, 3):
            line = self.ser.readline()
            logging.debug("line: %s" % line.replace('\n',''))
            if type(line) is str and len(line) > 0 and line[0] == "#" and line[-1] == '\n':
                readings = line[1:-1].split(",")
                if readings[0] in MODELS.keys():
                    logging.debug("found %s version %u" % (readings[0], int(readings[1])))
                    self.unpack = MODELS[readings[0]][int(readings[1])]
                    return
        raise Exception, "unable to identify model: %s" % line

    def write(self, value):
        self.ser.flushOutput()
        self.ser.write(value)

    def fetch(self):
        readings = self.unpack(self.ser.readline())
        readings['port'] = self.ser.port
        readings['at'] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ")
        delta = math.fabs(self.interval - readings['window'])
        if delta / self.interval > 0.1:
            logging.debug("polling drift is higher than 10%%, target is %u actual is %u" % (self.interval, readings['window']))
        return readings

def main():

    p = optparse.OptionParser()
    p.add_option('--port', '-p', dest="port", default=DEFAULT_PORT)
    p.add_option('--interval', '-i', dest="interval", default=DEFAULT_INTERVAL)
    p.add_option('--offset', '-o', dest="offset", default=None)
    p.add_option('--sensitivity', '-s', dest="sensitivity", default=None)
    p.add_option('--bps', '-b', dest="bps", default=DEFAULT_PORT_SPEED)
    p.add_option('--verbose', '-v', action="store_true", dest="verbose", default=False)
    p.add_option('--log', '-l', dest="log")
    options, _ = p.parse_args()
    init = []
    if options.offset != None:
        init.append("#C%s" % options.offset)
    if options.sensitivity != None:
        init.append("#D%s" % options.sensitivity)
    if options.verbose:
        lvl = logging.DEBUG
    else:
        lvl = logging.INFO
    logging.basicConfig(level=lvl, format=LOG_FORMAT, filename=options.log, filemode='w')
    energino = PyEnergino(options.port, options.bps, int(options.interval))
    energino.send_cmds(init)
    while True:
        energino.ser.flushInput()
        try:
            readings = energino.fetch()
        except KeyboardInterrupt:
            logging.debug("Bye!")
            sys.exit()
        except:
            logging.debug("0 [V] 0 [A] 0 [W] 0 [samples] 0 [window]")
        else:
            logging.info("%s [V] %s [A] %s [W] %s [samples] %s [window]" % (readings['voltage'], readings['current'], readings['power'], readings['samples'], readings['window']))

if __name__ == "__main__":
    main()
    <|endoftext|>


<commit_before>
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from uuid import UUID
from StringIO import StringIO
from errors import InvalidQueryFormat
from struct import unpack

__all__ = ['prepare', 'marshal', 'unmarshal']

def prepare(query, *args):
    result = StringIO()
    index = query.find('?')
    oldindex = 0
    count = 0

    while (index >= 0):
        result.write(query[oldindex:index])
        try:
            result.write(marshal(args[count]))
        except IndexError:
            raise InvalidQueryFormat("not enough arguments in substitution")

        oldindex = index + 1
        index = query.find('?', index + 1)
        count += 1
    result.write(query[oldindex:])

    if count < len(args):
        raise InvalidQueryFormat("too many arguments in substitution")

    return result.getvalue()

def marshal(term):
    if isinstance(term, long):
        return "%dL" % term
    elif isinstance(term, int):
        return "%d" % term
    elif isinstance(term, unicode):
        return "u'%s'" % term
    elif isinstance(term, str):
        return "'%s'" % term
    elif isinstance(term, UUID):
        if term.version == 1:
            return "timeuuid(\"%s\")" % str(term)
        else:
            return str(term)
    else:
        return str(term)

def unmarshal(bytestr, typestr):
    if typestr == "org.apache.cassandra.db.marshal.BytesType":
        return bytestr
    elif typestr == "org.apache.cassandra.db.marshal.AsciiType":
        return bytestr
    elif typestr == "org.apache.cassandra.db.marshal.UTF8Type":
        return bytestr.decode("utf8")
    elif typestr == "org.apache.cassandra.db.marshal.IntegerType":
        return decode_bigint(bytestr)
    elif typestr == "org.apache.cassandra.db.marshal.LongType":
        return unpack(">q", bytestr)[0]
    elif typestr == "org.apache.cassandra.db.marshal.LexicalUUIDType":
        return UUID(bytes=bytestr)
    elif typestr == "org.apache.cassandra.db.marshal.TimeUUIDType":
        return UUID(bytes=bytestr)
    else:
        return bytestr

def decode_bigint(term):
    val = int(term.encode('hex'), 16)
    if (ord(term[0]) & 128) != 0:
        val = val - (1 << (len(term) * 8))
    return val

<commit_msg>remove long term type<commit_after>
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from uuid import UUID
from StringIO import StringIO
from errors import InvalidQueryFormat
from struct import unpack

__all__ = ['prepare', 'marshal', 'unmarshal']

def prepare(query, *args):
    result = StringIO()
    index = query.find('?')
    oldindex = 0
    count = 0

    while (index >= 0):
        result.write(query[oldindex:index])
        try:
            result.write(marshal(args[count]))
        except IndexError:
            raise InvalidQueryFormat("not enough arguments in substitution")

        oldindex = index + 1
        index = query.find('?', index + 1)
        count += 1
    result.write(query[oldindex:])

    if count < len(args):
        raise InvalidQueryFormat("too many arguments in substitution")

    return result.getvalue()

def marshal(term):
    if isinstance(term, (long,int)):
        return "%d" % term
    elif isinstance(term, unicode):
        return "u'%s'" % term
    elif isinstance(term, str):
        return "'%s'" % term
    elif isinstance(term, UUID):
        if term.version == 1:
            return "timeuuid(\"%s\")" % str(term)
        else:
            return str(term)
    else:
        return str(term)

def unmarshal(bytestr, typestr):
    if typestr == "org.apache.cassandra.db.marshal.BytesType":
        return bytestr
    elif typestr == "org.apache.cassandra.db.marshal.AsciiType":
        return bytestr
    elif typestr == "org.apache.cassandra.db.marshal.UTF8Type":
        return bytestr.decode("utf8")
    elif typestr == "org.apache.cassandra.db.marshal.IntegerType":
        return decode_bigint(bytestr)
    elif typestr == "org.apache.cassandra.db.marshal.LongType":
        return unpack(">q", bytestr)[0]
    elif typestr == "org.apache.cassandra.db.marshal.LexicalUUIDType":
        return UUID(bytes=bytestr)
    elif typestr == "org.apache.cassandra.db.marshal.TimeUUIDType":
        return UUID(bytes=bytestr)
    else:
        return bytestr

def decode_bigint(term):
    val = int(term.encode('hex'), 16)
    if (ord(term[0]) & 128) != 0:
        val = val - (1 << (len(term) * 8))
    return val

<|endoftext|>


<commit_before>import itertools

import pendulum
from django.db.models import Q, F
from memoize import memoize

from bluebottle.projects.models import Project, ProjectPhaseLog
from bluebottle.tasks.models import Task, TaskMember, TaskStatusLog, TaskMemberStatusLog

class Statistics(object):
    def __init__(self, start=None, end=None):
        self.start = start
        self.end = end

    def date_filter(self, field='created'):
        if self.start and self.end:
            filter_args = {'{}__range'.format(field): (self.start, self.end)}
        elif self.start:
            filter_args = {'{}__gte'.format(field): self.start}
        elif self.end:
            filter_args = {'{}__lte'.format(field): self.end}
        else:
            filter_args = {}

        return Q(**filter_args)

    def end_date_filter(self, field='created'):
        if self.end:
            filter_args = {'{}__lte'.format(field): self.end}
        else:
            filter_args = {}

        return Q(**filter_args)

    @property
    @memoize(timeout=60 * 60)
    def participants_count(self):
        """ Total numbers of participants (members that started a project, or realized task member,
        or inititated a task)"""
        return len(self.participant_details())

    def participant_details(self):
        """Participants are defined as project initiators of a project (running, done or realised),
        task members (that applied for, got accepted for, or realised a task) or task initiators.
        If a member is one of the three (e.g. a project initiator or a task member or a task initiator),
        they are counted as one participant."""

        # NOTE: Queries just for reference.
        project_owners = Project.objects\
            .filter(self.date_filter('created'),
                    status__slug__in=('voting', 'voting-done', 'campaign', 'done-complete', 'done-incomplete'))\
            .values('owner_id', 'owner__email', 'created')\
            .annotate(id=F('owner_id'))\
            .annotate(email=F('owner__email'))\
            .annotate(action_date=F('created'))

        task_members = TaskMember.objects\
            .filter(self.date_filter('task__created'), status__in=('applied', 'accepted', 'realized'))\
            .values('member_id', 'member__email', 'task__created')\
            .annotate(id=F('member_id'))\
            .annotate(email=F('member__email'))\
            .annotate(action_date=F('task__created'))

        task_authors = Task.objects\
            .filter(self.date_filter('created'), status__in=('open', 'in progress', 'realized', 'full', 'closed'))\
            .values('author_id', 'author__email', 'created')\
            .annotate(id=F('author_id'))\
            .annotate(email=F('author__email'))\
            .annotate(action_date=F('created'))

        participants = dict()

        for member in itertools.chain(task_members, project_owners, task_authors):
            if participants.get(member['id']):
                if member['action_date'] < participants[member['id']]['action_date']:
                    participants[member['id']]['action_date'] = member['action_date']
            else:
                participants[member['id']] = member

        return sorted(participants.values(), key=lambda k: k['action_date'])

    # NOTE: Temporary Stats to count a special case of impact of considering only task members with status realised
    # on the
    # participation number
    @property
    @memoize(timeout=60 * 60)
    def participants_count_with_only_task_members_realized(self):
        """ Total numbers of participants (members that started a project, or realized task member,
        or inititated a task)"""
        return len(self.participant_details_with_only_task_members_realized())

    def participant_details_with_only_task_members_realized(self):
        """Participants are defined as project initiators of a project (running, done or realised),
        task members (that applied for, got accepted for, or realised a task) or task initiators.
        If a member is one of the three (e.g. a project initiator or a task member or a task initiator),
        they are counted as one participant."""

        project_owners = Project.objects\
            .filter(self.date_filter('created'),
                    status__slug__in=('voting', 'voting-done', 'campaign', 'done-complete', 'done-incomplete'))\
            .values('owner_id', 'owner__email', 'created')\
            .annotate(id=F('owner_id'))\
            .annotate(email=F('owner__email'))\
            .annotate(action_date=F('created'))

        task_members = TaskMember.objects\
            .filter(self.date_filter('task__created'), status='realized')\
            .values('member_id', 'member__email', 'task__created')\
            .annotate(id=F('member_id'))\
            .annotate(email=F('member__email'))\
            .annotate(action_date=F('task__created'))

        task_authors = Task.objects\
            .filter(self.date_filter('created'), status__in=('open', 'in progress', 'realized', 'full', 'closed'))\
            .values('author_id', 'author__email', 'created')\
            .annotate(id=F('author_id'))\
            .annotate(email=F('author__email'))\
            .annotate(action_date=F('created'))

        participants = dict()

        for member in itertools.chain(task_members, project_owners, task_authors):
            if participants.get(member['id']):
                if member['action_date'] < participants[member['id']]['action_date']:
                    participants[member['id']]['action_date'] = member['action_date']
            else:
                participants[member['id']] = member

        return sorted(participants.values(), key=lambda k: k['action_date'])

    # Projects Statistics
    @property
    @memoize(timeout=60 * 60)
    def projects_total(self):
        return Project.objects.filter(created__lte=self.end).count()

    @memoize(timeout=60 * 60)
    def get_projects_count_by_theme(self, theme):
        projects_count = Project.objects\
            .filter(created__lte=self.end, theme__slug=theme)\
            .count()

        return projects_count

    @memoize(timeout=60 * 60)
    def get_projects_count_by_last_status(self, statuses):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'), project__created__lte=self.end)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')

        count = 0
        for log in logs:
            if log.status.slug in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_projects_status_count_by_location_group(self, location_group, statuses):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'),
                    project__location__group__name=location_group,
                    project__created__lte=self.end)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')

        count = 0
        for log in logs:
            if log.status.slug in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_projects_status_count_by_theme(self, theme, statuses):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'),
                    project__theme__slug=theme,
                    project__created__lte=self.end)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')

        count = 0
        for log in logs:
            if log.status.slug in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_projects_by_location_group(self, location_group):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'), project__location__group__name=location_group)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')
        return logs

    @property
    @memoize(timeout=60 * 60)
    def projects_successful(self):
        """ Total number of successful (done-complete, incomplete and voting done) projects """
        return self.get_projects_count_by_last_status(['done-complete', 'done-incomplete', 'voting-done'])

    @property
    @memoize(timeout=60 * 60)
    def projects_running(self):
        """ Total number of running (voting, campaign) projects """
        return self.get_projects_count_by_last_status(['voting', 'campaign'])

    @property
    @memoize(timeout=300)
    def projects_complete(self):
        """ Total number of complete (done-complete, voting-done) projects"""
        return self.get_projects_count_by_last_status(['done-complete', 'voting-done'])

    @property
    @memoize(timeout=60 * 60)
    def projects_online(self):
        """ Total number of projects that have been in campaign mode"""
        return Project.objects.filter(self.date_filter('campaign_started'),
                                      status__slug__in=('voting', 'campaign')).count()

    # Tasks Statistics
    @property
    @memoize(timeout=60 * 60)
    def tasks_total(self):
        return Task.objects.filter(created__lte=self.end).count()

    @memoize(timeout=60 * 60)
    def get_tasks_count_by_last_status(self, statuses):
        logs = TaskStatusLog.objects\
            .filter(self.end_date_filter('start'), task__created__lte=self.end)\
            .distinct('task__id')\
            .order_by('-task__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_tasks_status_count_by_location_group(self, location_group, statuses):
        logs = TaskStatusLog.objects\
            .filter(self.end_date_filter('start'),
                    task__project__location__group__name=location_group,
                    task__created__lte=self.end)\
            .distinct('task__id')\
            .order_by('-task__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_tasks_status_count_by_theme(self, theme, statuses):
        logs = TaskStatusLog.objects\
            .filter(self.end_date_filter('start'),
                    task__project__theme__slug=theme,
                    task__created__lte=self.end)\
            .distinct('task__id')\
            .order_by('-task__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    # Task Member Statistics
    @property
    @memoize(timeout=60 * 60)
    def task_members_total(self):
        return TaskMember.objects.filter(created__lte=self.end).count()

    @memoize(timeout=60 * 60)
    def get_task_members_count_by_last_status(self, statuses):
        logs = TaskMemberStatusLog.objects\
            .filter(self.end_date_filter('start'), task_member__created__lte=self.end)\
            .distinct('task_member__id')\
            .order_by('-task_member__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    @property
    @memoize(timeout=60 * 60)
    def task_members(self):
        """ Total number of realized task members """
        logs = TaskMemberStatusLog.objects \
            .filter(self.end_date_filter('start'), task_member__task__created__lte=self.end) \
            .distinct('task_member__id') \
            .order_by('-task_member__id', '-start')

        count = 0
        for log in logs:
            if log.status == 'realized':
                count += 1
        return count

    @property
    @memoize(timeout=60 * 60)
    def unconfirmed_task_members(self):
        """ Total number of unconfirmed task members """
        now = pendulum.now()
        if self.end <= now.subtract(days=10):
            logs = TaskMemberStatusLog.objects \
                .filter(self.end_date_filter('start'), task_member__task__deadline__lte=self.end.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')
        else:
            logs = TaskMemberStatusLog.objects \
                .filter(start__lte=now, task_member__task__deadline__lte=now.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')

        count = 0
        for log in logs:
            if log.status == 'accepted':
                count += 1
        return count

    @property
    @memoize(timeout=60 * 60)
    def unconfirmed_task_members_task_count(self):
        """ Total number of task belonging to unconfirmed task members """
        now = pendulum.now()
        if self.end <= now.subtract(days=10):
            logs = TaskMemberStatusLog.objects \
                .filter(self.end_date_filter('start'), task_member__task__deadline__lte=self.end.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')
        else:
            logs = TaskMemberStatusLog.objects \
                .filter(start__lte=now, task_member__task__deadline__lte=now.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')

        task_ids = set()

        for log in logs:
            if log.status == 'accepted':
                task_ids.add(log.task_member.task.id)

        return len(task_ids)

    @property
    @memoize(timeout=60 * 60)
    def time_spent(self):
        """ Total amount of time spent on realized tasks """
        logs = TaskMemberStatusLog.objects\
            .filter(self.end_date_filter('start'), task_member__task__created__lte=self.end) \
            .distinct('task_member__id') \
            .order_by('-task_member__id', '-start') \

        count = 0
        for log in logs:
            if log.status == 'realized':
                count += log.task_member.time_spent

        return count

    def __repr__(self):
        start = self.start.strftime('%s') if self.start else 'none'
        end = self.end.strftime('%s') if self.end else 'none'
        return 'Statistics({},{})'.format(start, end)
<commit_msg>remove unused metric<commit_after>import itertools

import pendulum
from django.db.models import Q, F
from memoize import memoize

from bluebottle.projects.models import Project, ProjectPhaseLog
from bluebottle.tasks.models import Task, TaskMember, TaskStatusLog, TaskMemberStatusLog

class Statistics(object):
    def __init__(self, start=None, end=None):
        self.start = start
        self.end = end

    def date_filter(self, field='created'):
        if self.start and self.end:
            filter_args = {'{}__range'.format(field): (self.start, self.end)}
        elif self.start:
            filter_args = {'{}__gte'.format(field): self.start}
        elif self.end:
            filter_args = {'{}__lte'.format(field): self.end}
        else:
            filter_args = {}

        return Q(**filter_args)

    def end_date_filter(self, field='created'):
        if self.end:
            filter_args = {'{}__lte'.format(field): self.end}
        else:
            filter_args = {}

        return Q(**filter_args)

    @property
    @memoize(timeout=60 * 60)
    def participants_count(self):
        """ Total numbers of participants (members that started a project, or realized task member,
        or inititated a task)"""
        return len(self.participant_details())

    def participant_details(self):
        """Participants are defined as project initiators of a project (running, done or realised),
        task members (that applied for, got accepted for, or realised a task) or task initiators.
        If a member is one of the three (e.g. a project initiator or a task member or a task initiator),
        they are counted as one participant."""

        # NOTE: Queries just for reference.
        project_owners = Project.objects\
            .filter(self.date_filter('created'),
                    status__slug__in=('voting', 'voting-done', 'campaign', 'done-complete', 'done-incomplete'))\
            .values('owner_id', 'owner__email', 'created')\
            .annotate(id=F('owner_id'))\
            .annotate(email=F('owner__email'))\
            .annotate(action_date=F('created'))

        task_members = TaskMember.objects\
            .filter(self.date_filter('task__created'), status__in=('applied', 'accepted', 'realized'))\
            .values('member_id', 'member__email', 'task__created')\
            .annotate(id=F('member_id'))\
            .annotate(email=F('member__email'))\
            .annotate(action_date=F('task__created'))

        task_authors = Task.objects\
            .filter(self.date_filter('created'), status__in=('open', 'in progress', 'realized', 'full', 'closed'))\
            .values('author_id', 'author__email', 'created')\
            .annotate(id=F('author_id'))\
            .annotate(email=F('author__email'))\
            .annotate(action_date=F('created'))

        participants = dict()

        for member in itertools.chain(task_members, project_owners, task_authors):
            if participants.get(member['id']):
                if member['action_date'] < participants[member['id']]['action_date']:
                    participants[member['id']]['action_date'] = member['action_date']
            else:
                participants[member['id']] = member

        return sorted(participants.values(), key=lambda k: k['action_date'])

    # NOTE: Temporary Stats to count a special case of impact of considering only task members with status realised
    # on the
    # participation number
    @property
    @memoize(timeout=60 * 60)
    def participants_count_with_only_task_members_realized(self):
        """ Total numbers of participants (members that started a project, or realized task member,
        or inititated a task)"""
        return len(self.participant_details_with_only_task_members_realized())

    def participant_details_with_only_task_members_realized(self):
        """Participants are defined as project initiators of a project (running, done or realised),
        task members (that applied for, got accepted for, or realised a task) or task initiators.
        If a member is one of the three (e.g. a project initiator or a task member or a task initiator),
        they are counted as one participant."""

        project_owners = Project.objects\
            .filter(self.date_filter('created'),
                    status__slug__in=('voting', 'voting-done', 'campaign', 'done-complete', 'done-incomplete'))\
            .values('owner_id', 'owner__email', 'created')\
            .annotate(id=F('owner_id'))\
            .annotate(email=F('owner__email'))\
            .annotate(action_date=F('created'))

        task_members = TaskMember.objects\
            .filter(self.date_filter('task__created'), status='realized')\
            .values('member_id', 'member__email', 'task__created')\
            .annotate(id=F('member_id'))\
            .annotate(email=F('member__email'))\
            .annotate(action_date=F('task__created'))

        task_authors = Task.objects\
            .filter(self.date_filter('created'), status__in=('open', 'in progress', 'realized', 'full', 'closed'))\
            .values('author_id', 'author__email', 'created')\
            .annotate(id=F('author_id'))\
            .annotate(email=F('author__email'))\
            .annotate(action_date=F('created'))

        participants = dict()

        for member in itertools.chain(task_members, project_owners, task_authors):
            if participants.get(member['id']):
                if member['action_date'] < participants[member['id']]['action_date']:
                    participants[member['id']]['action_date'] = member['action_date']
            else:
                participants[member['id']] = member

        return sorted(participants.values(), key=lambda k: k['action_date'])

    # Projects Statistics
    @property
    @memoize(timeout=60 * 60)
    def projects_total(self):
        return Project.objects.filter(created__lte=self.end).count()

    @memoize(timeout=60 * 60)
    def get_projects_count_by_theme(self, theme):
        projects_count = Project.objects\
            .filter(created__lte=self.end, theme__slug=theme)\
            .count()

        return projects_count

    @memoize(timeout=60 * 60)
    def get_projects_count_by_last_status(self, statuses):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'), project__created__lte=self.end)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')

        count = 0
        for log in logs:
            if log.status.slug in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_projects_status_count_by_location_group(self, location_group, statuses):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'),
                    project__location__group__name=location_group,
                    project__created__lte=self.end)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')

        count = 0
        for log in logs:
            if log.status.slug in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_projects_status_count_by_theme(self, theme, statuses):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'),
                    project__theme__slug=theme,
                    project__created__lte=self.end)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')

        count = 0
        for log in logs:
            if log.status.slug in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_projects_by_location_group(self, location_group):
        logs = ProjectPhaseLog.objects\
            .filter(self.end_date_filter('start'), project__location__group__name=location_group)\
            .distinct('project__id')\
            .order_by('-project__id', '-start')
        return logs

    @property
    @memoize(timeout=60 * 60)
    def projects_successful(self):
        """ Total number of successful (done-complete, incomplete and voting done) projects """
        return self.get_projects_count_by_last_status(['done-complete', 'done-incomplete', 'voting-done'])

    @property
    @memoize(timeout=60 * 60)
    def projects_running(self):
        """ Total number of running (voting, campaign) projects """
        return self.get_projects_count_by_last_status(['voting', 'campaign'])

    @property
    @memoize(timeout=300)
    def projects_complete(self):
        """ Total number of complete (done-complete, voting-done) projects"""
        return self.get_projects_count_by_last_status(['done-complete', 'voting-done'])

    @property
    @memoize(timeout=60 * 60)
    def projects_online(self):
        """ Total number of projects that have been in campaign mode"""
        return Project.objects.filter(self.date_filter('campaign_started'),
                                      status__slug__in=('voting', 'campaign')).count()

    # Tasks Statistics
    @property
    @memoize(timeout=60 * 60)
    def tasks_total(self):
        return Task.objects.filter(created__lte=self.end).count()

    @memoize(timeout=60 * 60)
    def get_tasks_count_by_last_status(self, statuses):
        logs = TaskStatusLog.objects\
            .filter(self.end_date_filter('start'), task__created__lte=self.end)\
            .distinct('task__id')\
            .order_by('-task__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_tasks_status_count_by_location_group(self, location_group, statuses):
        logs = TaskStatusLog.objects\
            .filter(self.end_date_filter('start'),
                    task__project__location__group__name=location_group,
                    task__created__lte=self.end)\
            .distinct('task__id')\
            .order_by('-task__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    @memoize(timeout=60 * 60)
    def get_tasks_status_count_by_theme(self, theme, statuses):
        logs = TaskStatusLog.objects\
            .filter(self.end_date_filter('start'),
                    task__project__theme__slug=theme,
                    task__created__lte=self.end)\
            .distinct('task__id')\
            .order_by('-task__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    # Task Member Statistics
    @property
    @memoize(timeout=60 * 60)
    def task_members_total(self):
        return TaskMember.objects.filter(created__lte=self.end).count()

    @memoize(timeout=60 * 60)
    def get_task_members_count_by_last_status(self, statuses):
        logs = TaskMemberStatusLog.objects\
            .filter(self.end_date_filter('start'), task_member__created__lte=self.end)\
            .distinct('task_member__id')\
            .order_by('-task_member__id', '-start')

        count = 0
        for log in logs:
            if log.status in statuses:
                count += 1
        return count

    @property
    @memoize(timeout=60 * 60)
    def task_members(self):
        """ Total number of realized task members """
        logs = TaskMemberStatusLog.objects \
            .filter(self.end_date_filter('start'), task_member__task__created__lte=self.end) \
            .distinct('task_member__id') \
            .order_by('-task_member__id', '-start')

        count = 0
        for log in logs:
            if log.status == 'realized':
                count += 1
        return count

    @property
    @memoize(timeout=60 * 60)
    def unconfirmed_task_members(self):
        """ Total number of unconfirmed task members """
        now = pendulum.now()
        if self.end <= now.subtract(days=10):
            logs = TaskMemberStatusLog.objects \
                .filter(self.end_date_filter('start'), task_member__task__deadline__lte=self.end.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')
        else:
            logs = TaskMemberStatusLog.objects \
                .filter(start__lte=now, task_member__task__deadline__lte=now.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')

        count = 0
        for log in logs:
            if log.status == 'accepted':
                count += 1
        return count

    @property
    @memoize(timeout=60 * 60)
    def unconfirmed_task_members_task_count(self):
        """ Total number of task belonging to unconfirmed task members """
        now = pendulum.now()
        if self.end <= now.subtract(days=10):
            logs = TaskMemberStatusLog.objects \
                .filter(self.end_date_filter('start'), task_member__task__deadline__lte=self.end.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')
        else:
            logs = TaskMemberStatusLog.objects \
                .filter(start__lte=now, task_member__task__deadline__lte=now.subtract(days=10)) \
                .distinct('task_member__id') \
                .order_by('-task_member__id', '-start')

        task_ids = set()

        for log in logs:
            if log.status == 'accepted':
                task_ids.add(log.task_member.task.id)

        return len(task_ids)

    def __repr__(self):
        start = self.start.strftime('%s') if self.start else 'none'
        end = self.end.strftime('%s') if self.end else 'none'
        return 'Statistics({},{})'.format(start, end)
<|endoftext|>