Пример #1
0
def handle_vip(addon, version, user):
    msg = u'VIP app updated'

    # Add to escalation queue
    EscalationQueue.objects.get_or_create(addon=addon)

    # Create comm note
    create_comm_note(addon, version, user, msg, note_type=comm.ESCALATION,
                     perms={'developer': False})

    # Log action
    amo.log(amo.LOG.ESCALATION_VIP_APP, addon, version, created=datetime.now(),
            details={'comments': msg})
    log.info(u'[app:%s] escalated - %s' % (addon.name, msg))

    # Special senior reviewer email.
    if not waffle.switch_is_active('comm-dashboard'):
        context = {'name': addon.name,
                   'review_url': absolutify(reverse('reviewers.apps.review',
                                                     args=[addon.app_slug],
                                                     add_prefix=False)),
                   'SITE_URL': settings.SITE_URL}
        send_mail(u'%s: %s' % (msg, addon.name),
                   'developers/emails/vip_escalation.ltxt', context,
                   [settings.MKT_SENIOR_EDITORS_EMAIL])
Пример #2
0
def app_summary(request, addon_id):
    app = get_object_or_404(Webapp.with_deleted, pk=addon_id)

    if 'prioritize' in request.POST and not app.priority_review:
        app.update(priority_review=True)
        msg = u'Priority Review Requested'
        # Create notes and log entries.
        create_comm_note(app, app.latest_version, request.amo_user, msg,
                         note_type=comm.NO_ACTION)
        amo.log(amo.LOG.PRIORITY_REVIEW_REQUESTED, app, app.latest_version,
                created=datetime.now(), details={'comments': msg})

    authors = (app.authors.filter(addonuser__role__in=(amo.AUTHOR_ROLE_DEV,
                                                       amo.AUTHOR_ROLE_OWNER))
                          .order_by('display_name'))

    if app.premium and app.premium.price:
        price = app.premium.price
    else:
        price = None

    purchases, refunds = _app_purchases_and_refunds(app)
    payment_account = False
    # TODO: fixme for multiple accounts
    if hasattr(app, 'single_pay_account'):
        try:
            payment_account = app.single_pay_account().payment_account
        except ValueError:
            pass
    return render(request, 'lookup/app_summary.html',
                  {'abuse_reports': app.abuse_reports.count(), 'app': app,
                   'authors': authors, 'downloads': _app_downloads(app),
                   'purchases': purchases, 'refunds': refunds, 'price': price,
                   'payment_account': payment_account})
Пример #3
0
 def publish(self, request, *args, **kwargs):
     obj = self.get_object()
     obj.publish()
     create_comm_note(obj.extension, obj, request.user,
                      request.DATA.get('message', ''),
                      note_type=comm.APPROVAL)
     return Response(status=status.HTTP_202_ACCEPTED)
Пример #4
0
def version_edit(request, addon_id, addon, version_id):
    show_features = addon.is_packaged
    formdata = request.POST if request.method == "POST" else None
    version = get_object_or_404(Version, pk=version_id, addon=addon)
    version.addon = addon  # Avoid extra useless query.
    form = AppVersionForm(formdata, instance=version)
    all_forms = [form]

    if show_features:
        appfeatures = version.features
        appfeatures_form = AppFeaturesForm(request.POST or None, instance=appfeatures)
        all_forms.append(appfeatures_form)

    if request.method == "POST" and all(f.is_valid() for f in all_forms):
        [f.save() for f in all_forms]

        if f.data.get("approvalnotes"):
            create_comm_note(addon, version, request.user, f.data["approvalnotes"], note_type=comm.REVIEWER_COMMENT)

        messages.success(request, _("Version successfully edited."))
        return redirect(addon.get_dev_url("versions"))

    context = {"addon": addon, "version": version, "form": form}

    if show_features:
        context.update(
            {
                "appfeatures_form": appfeatures_form,
                "appfeatures": appfeatures,
                "feature_list": [unicode(f) for f in appfeatures.to_list()],
            }
        )

    return render(request, "developers/apps/version_edit.html", context)
Пример #5
0
 def reject(self, request, *args, **kwargs):
     obj = self.get_object()
     obj.reject()
     create_comm_note(obj.extension, obj, request.user,
                      request.data.get('message', ''),
                      note_type=comm.REJECTION)
     return Response(status=status.HTTP_202_ACCEPTED)
Пример #6
0
 def reject(self, request, *args, **kwargs):
     obj = self.get_object()
     obj.reject()
     create_comm_note(obj.extension, obj, request.user,
                      request.data.get('message', ''),
                      note_type=comm.REJECTION)
     return Response(status=status.HTTP_202_ACCEPTED)
Пример #7
0
def app_summary(request, addon_id):
    app = get_object_or_404(Webapp.with_deleted, pk=addon_id)

    if 'prioritize' in request.POST and not app.priority_review:
        app.update(priority_review=True)
        msg = u'Priority Review Requested'
        # Create notes and log entries.
        create_comm_note(app, app.latest_version, request.amo_user, msg,
                         note_type=comm.NO_ACTION)
        amo.log(amo.LOG.PRIORITY_REVIEW_REQUESTED, app, app.latest_version,
                created=datetime.now(), details={'comments': msg})

    authors = (app.authors.filter(addonuser__role__in=(amo.AUTHOR_ROLE_DEV,
                                                       amo.AUTHOR_ROLE_OWNER))
                          .order_by('display_name'))

    if app.premium and app.premium.price:
        price = app.premium.price
    else:
        price = None

    purchases, refunds = _app_purchases_and_refunds(app)
    provider_portals = get_payment_provider_portals(app=app)

    return render(request, 'lookup/app_summary.html',
                  {'abuse_reports': app.abuse_reports.count(), 'app': app,
                   'authors': authors, 'downloads': _app_downloads(app),
                   'purchases': purchases, 'refunds': refunds, 'price': price,
                   'provider_portals': provider_portals})
Пример #8
0
    def test_create_note_existing_thread(self):
        # Initial note.
        thread, note = create_comm_note(self.app, self.app.current_version,
                                        self.user, 'huehue')

        # Second note from contact.
        thread, reply = create_comm_note(self.app,
                                         self.app.current_version,
                                         self.contact,
                                         'euheuh!',
                                         note_type=comm.REJECTION)

        # Mark read by author.
        eq_(reply.read_by_users.count(), 1)

        # Third person joins thread.
        thread, last_word = create_comm_note(self.app,
                                             self.app.current_version,
                                             user_factory(),
                                             'euheuh!',
                                             note_type=comm.MORE_INFO_REQUIRED)

        # More checking that joining a thread marks all old notes as read.
        eq_(thread.thread_cc.count(), 3)
        eq_(note.read_by_users.count(), 3)
        eq_(reply.read_by_users.count(), 2)
        eq_(last_word.read_by_users.count(), 1)
Пример #9
0
def prioritize_app(app, user):
    app.update(priority_review=True)
    msg = u'Priority Review Requested'
    # Create notes and log entries.
    create_comm_note(app, app.latest_version, user, msg,
                     note_type=comm.PRIORITY_REVIEW_REQUESTED)
    mkt.log(mkt.LOG.PRIORITY_REVIEW_REQUESTED, app, app.latest_version,
            created=datetime.now(), details={'comments': msg})
Пример #10
0
def prioritize_app(app, user):
    app.update(priority_review=True)
    msg = u'Priority Review Requested'
    # Create notes and log entries.
    create_comm_note(app, app.latest_version, user, msg,
                     note_type=comm.PRIORITY_REVIEW_REQUESTED)
    mkt.log(mkt.LOG.PRIORITY_REVIEW_REQUESTED, app, app.latest_version,
            created=datetime.now(), details={'comments': msg})
Пример #11
0
 def publish(self, request, *args, **kwargs):
     obj = self.get_object()
     obj.publish()
     create_comm_note(obj.extension,
                      obj,
                      request.user,
                      request.DATA.get('message', ''),
                      note_type=comm.APPROVAL)
     return Response(status=status.HTTP_202_ACCEPTED)
Пример #12
0
    def test_create_note_existing_thread(self):
        # Initial note.
        thread, note = create_comm_note(
            self.extension, self.extension.latest_version, self.user, 'huehue')

        # Second person joins thread.
        thread, last_word = create_comm_note(
            self.extension, self.extension.latest_version, user_factory(),
            'euheuh!', note_type=comm.MORE_INFO_REQUIRED)

        eq_(thread.thread_cc.count(), 2)
Пример #13
0
def log_reviewer_action(addon, user, msg, action, **kwargs):
    create_comm_note(addon,
                     addon.latest_version,
                     user,
                     msg,
                     note_type=comm.ACTION_MAP(action.id))
    mkt.log(action,
            addon,
            addon.latest_version,
            details={'comments': msg},
            **kwargs)
Пример #14
0
    def save(self, *args, **kw):
        if self.data['notes']:
            create_comm_note(self.instance, self.instance.versions.latest(),
                             self.request.user, self.data['notes'],
                             note_type=comm.SUBMISSION)
        self.instance = super(AppDetailsBasicForm, self).save(commit=True)

        for tag_text in self.cleaned_data['tags']:
            Tag(tag_text=tag_text).save_tag(self.instance)

        return self.instance
Пример #15
0
def escalate_app(app, version, user, msg, log_type):
    # Add to escalation queue
    EscalationQueue.objects.get_or_create(addon=app)

    # Create comm note
    create_comm_note(app, version, user, msg,
                     note_type=comm.ACTION_MAP(log_type))

    # Log action
    mkt.log(log_type, app, version, created=datetime.now(),
            details={'comments': msg})
    log.info(u'[app:%s] escalated - %s' % (app.name, msg))
Пример #16
0
def escalate_app(app, version, user, msg, log_type):
    # Add to escalation queue
    EscalationQueue.objects.get_or_create(addon=app)

    # Create comm note
    create_comm_note(app, version, user, msg,
                     note_type=comm.ACTION_MAP(log_type))

    # Log action
    mkt.log(log_type, app, version, created=datetime.now(),
            details={'comments': msg})
    log.info(u'[app:%s] escalated - %s' % (app.name, msg))
Пример #17
0
    def save(self, *args, **kw):
        if self.data['notes']:
            create_comm_note(self.instance, self.instance.versions.latest(),
                             self.request.user, self.data['notes'],
                             note_type=comm.SUBMISSION)
        self.instance = super(AppDetailsBasicForm, self).save(commit=True)
        uses_flash = self.cleaned_data.get('flash')
        af = self.instance.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        return self.instance
Пример #18
0
    def flag(cls, addon, event, message=None):
        cls.objects.get_or_create(addon=addon)
        version = addon.current_version or addon.latest_version
        if message:
            mkt.log(event, addon, version, details={"comments": message})
        else:
            mkt.log(event, addon, version)

        # TODO: if we ever get rid of ActivityLog for reviewer notes, replace
        # all flag calls to use the comm constant and not have to use
        # ACTION_MAP.
        create_comm_note(addon, version, None, message, note_type=comm.ACTION_MAP(event))
Пример #19
0
def app_summary(request, addon_id):
    app = get_object_or_404(Webapp.with_deleted, pk=addon_id)

    if 'prioritize' in request.POST and not app.priority_review:
        app.update(priority_review=True)
        msg = u'Priority Review Requested'
        # Create notes and log entries.
        create_comm_note(app, app.latest_version, request.user, msg,
                         note_type=comm.PRIORITY_REVIEW_REQUESTED)
        amo.log(amo.LOG.PRIORITY_REVIEW_REQUESTED, app, app.latest_version,
                created=datetime.now(), details={'comments': msg})

    authors = (app.authors.filter(addonuser__role__in=(amo.AUTHOR_ROLE_DEV,
                                                       amo.AUTHOR_ROLE_OWNER))
                          .order_by('display_name'))

    if app.premium and app.premium.price:
        price = app.premium.price
    else:
        price = None

    purchases, refunds = _app_purchases_and_refunds(app)
    provider_portals = get_payment_provider_portals(app=app)
    versions = None

    status_form = APIStatusForm(initial={
        'status': amo.STATUS_CHOICES_API[app.status]
    })
    version_status_forms = {}
    if app.is_packaged:
        versions = app.versions.all().order_by('-created')
        for v in versions:
            version_status_forms[v.pk] = APIFileStatusForm(initial={
                'status': amo.STATUS_CHOICES_API[v.all_files[0].status]
            })

    permissions = {}
    if app.latest_version:
        permissions = app.latest_version.manifest.get('permissions', {})

    return render(request, 'lookup/app_summary.html', {
        'abuse_reports': app.abuse_reports.count(), 'app': app,
        'authors': authors, 'downloads': _app_downloads(app),
        'purchases': purchases, 'refunds': refunds, 'price': price,
        'provider_portals': provider_portals,
        'status_form': status_form, 'versions': versions,
        'is_tarako': app.tags.filter(tag_text=QUEUE_TARAKO).exists(),
        'tarako_review':
            app.additionalreview_set.latest_for_queue(QUEUE_TARAKO),
        'version_status_forms': version_status_forms,
        'permissions': permissions,
    })
Пример #20
0
    def test_create_note_existing_thread(self):
        # Initial note.
        thread, note = create_comm_note(self.extension,
                                        self.extension.latest_version,
                                        self.user, 'huehue')

        # Second person joins thread.
        thread, last_word = create_comm_note(self.extension,
                                             self.extension.latest_version,
                                             user_factory(),
                                             'euheuh!',
                                             note_type=comm.MORE_INFO_REQUIRED)

        eq_(thread.thread_cc.count(), 2)
Пример #21
0
    def save(self, *args, **kw):
        if self.data['notes']:
            create_comm_note(self.instance,
                             self.instance.versions.latest(),
                             self.request.user,
                             self.data['notes'],
                             note_type=comm.SUBMISSION)
        self.instance = super(AppDetailsBasicForm, self).save(commit=True)
        uses_flash = self.cleaned_data.get('flash')
        af = self.instance.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        return self.instance
Пример #22
0
    def test_create_note_existing_thread(self):
        # Initial note.
        thread, note = create_comm_note(self.app, self.app.current_version, self.user, "huehue")

        # Second note from contact.
        thread, reply = create_comm_note(
            self.app, self.app.current_version, self.contact, "euheuh!", note_type=comm.REJECTION
        )

        # Third person joins thread.
        thread, last_word = create_comm_note(
            self.app, self.app.current_version, user_factory(), "euheuh!", note_type=comm.MORE_INFO_REQUIRED
        )

        eq_(thread.thread_cc.count(), 3)
Пример #23
0
    def create_note(self, action):
        """
        Permissions default to developers + reviewers + Mozilla contacts.
        For escalation/comment, exclude the developer from the conversation.
        """
        details = {'comments': self.data['comments'],
                   'reviewtype': self.review_type}
        if self.files:
            details['files'] = [f.id for f in self.files]

        # Commbadge (the future).
        perm_overrides = {
            comm.ESCALATION: {'developer': False},
            comm.REVIEWER_COMMENT: {'developer': False},
        }
        note_type = comm.ACTION_MAP(action.id)
        self.comm_thread, self.comm_note = create_comm_note(
            self.addon, self.version, self.request.amo_user,
            self.data['comments'], note_type=note_type,
            # Ignore switch so we don't have to re-migrate new notes.
            perms=perm_overrides.get(note_type), no_switch=True,
            attachments=self.attachment_formset)

        # ActivityLog (ye olde).
        amo.log(action, self.addon, self.version, user=self.user.get_profile(),
                created=datetime.now(), details=details,
                attachments=self.attachment_formset)
Пример #24
0
 def _create(self, note_type, author=None):
     author = author or self.reviewer
     return create_comm_note(self.app,
                             self.app.current_version,
                             author,
                             'Test Comment',
                             note_type=note_type)
Пример #25
0
    def test_create_thread(self):
        # Default permissions.
        thread, note = create_comm_note(
            self.app, self.app.current_version, self.user, 'huehue',
            note_type=comm.APPROVAL)

        # Check Thread.
        eq_(thread.addon, self.app)
        eq_(thread.version, self.app.current_version)
        expected = {
            'public': False, 'developer': True, 'reviewer': True,
            'senior_reviewer': True, 'mozilla_contact': True, 'staff': True}
        for perm, has_perm in expected.items():
            eq_(getattr(thread, 'read_permission_%s' % perm), has_perm, perm)

        # Check Note.
        eq_(note.thread, thread)
        eq_(note.author, self.user)
        eq_(note.body, 'huehue')
        eq_(note.note_type, comm.APPROVAL)

        # Check CC.
        eq_(thread.thread_cc.count(), 2)
        assert thread.thread_cc.filter(user=self.contact).exists()
        assert thread.thread_cc.filter(user=self.user).exists()

        # Check Reads.
        eq_(note.read_by_users.count(), 2)
Пример #26
0
    def create_note(self, action):
        """
        Permissions default to developers + reviewers + Mozilla contacts.
        For escalation/comment, exclude the developer from the conversation.
        """
        details = {'comments': self.data['comments'],
                   'reviewtype': self.review_type}
        if self.files:
            details['files'] = [f.id for f in self.files]

        # Commbadge (the future).
        perm_overrides = {
            comm.ESCALATION: {'developer': False},
            comm.REVIEWER_COMMENT: {'developer': False},
        }
        note_type = comm.ACTION_MAP(action.id)
        self.comm_thread, self.comm_note = create_comm_note(
            self.addon, self.version, self.request.amo_user,
            self.data['comments'], note_type=note_type,
            # Ignore switch so we don't have to re-migrate new notes.
            perms=perm_overrides.get(note_type), no_switch=True,
            attachments=self.attachment_formset)

        # ActivityLog (ye olde).
        amo.log(action, self.addon, self.version, user=self.user,
                created=datetime.now(), details=details,
                attachments=self.attachment_formset)
Пример #27
0
    def create_note(self, action):
        """
        Permissions default to developers + reviewers + Mozilla contacts.
        For escalation/comment, exclude the developer from the conversation.
        """
        details = {'comments': self.data['comments'],
                   'reviewtype': self.review_type}
        if self.files:
            details['files'] = [f.id for f in self.files]

        tested = self.get_tested()  # You really should...
        if tested:
            self.data['comments'] += '\n\n%s' % tested

        # Commbadge (the future).
        note_type = comm.ACTION_MAP(action.id)
        self.comm_thread, self.comm_note = create_comm_note(
            self.addon, self.version, self.request.user,
            self.data['comments'], note_type=note_type,
            attachments=self.attachment_formset)

        # ActivityLog (ye olde).
        mkt.log(action, self.addon, self.version, user=self.user,
                created=datetime.now(), details=details,
                attachments=self.attachment_formset)
Пример #28
0
    def flag(cls, addon, event, message=None):
        cls.objects.get_or_create(addon=addon)
        version = addon.current_version or addon.latest_version
        if message:
            mkt.log(event, addon, version, details={'comments': message})
        else:
            mkt.log(event, addon, version)

        # TODO: if we ever get rid of ActivityLog for reviewer notes, replace
        # all flag calls to use the comm constant and not have to use
        # ACTION_MAP.
        create_comm_note(addon,
                         version,
                         None,
                         message,
                         note_type=comm.ACTION_MAP(event))
Пример #29
0
    def create_note(self, action):
        """
        Permissions default to developers + reviewers + Mozilla contacts.
        For escalation/comment, exclude the developer from the conversation.
        """
        details = {
            'comments': self.data['comments'],
            'reviewtype': self.review_type
        }
        if self.files:
            details['files'] = [f.id for f in self.files]

        tested = self.get_tested()  # You really should...
        if tested:
            self.data['comments'] += '\n\n%s' % tested

        # Commbadge (the future).
        note_type = comm.ACTION_MAP(action.id)
        self.comm_thread, self.comm_note = create_comm_note(
            self.addon,
            self.version,
            self.request.user,
            self.data['comments'],
            note_type=note_type,
            attachments=self.attachment_formset)

        # ActivityLog (ye olde).
        mkt.log(action,
                self.addon,
                self.version,
                user=self.user,
                created=datetime.now(),
                details=details)
Пример #30
0
    def create(self, request, *args, **kwargs):
        thread = get_object_or_404(CommunicationThread, id=kwargs['thread_id'])

        # Validate note.
        form = forms.CreateCommNoteForm(request.DATA)
        if not form.is_valid():
            return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)
        note_type = form.cleaned_data['note_type']

        if not self._has_create_perms(request, thread, request.user,
                                      note_type):
            return Response(
                'Only developers can make developer comments. '
                'Only reviewers can make reviewer comments.',
                status=status.HTTP_403_FORBIDDEN)

        # Create notes.
        thread, note = create_comm_note(thread.addon,
                                        thread.version,
                                        self.request.user,
                                        form.cleaned_data['body'],
                                        note_type=note_type)

        return Response(NoteSerializer(note, context={
            'request': request
        }).data,
                        status=status.HTTP_201_CREATED)
Пример #31
0
    def create(self, request, *args, **kwargs):
        if not waffle.switch_is_active('comm-dashboard'):
            return Response(status=status.HTTP_403_FORBIDDEN)

        thread = get_object_or_404(CommunicationThread, id=kwargs['thread_id'])

        # Validate note.
        form = forms.CreateCommNoteForm(request.DATA)
        if not form.is_valid():
            return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)
        note_type = form.cleaned_data['note_type']

        if (note_type == comm.DEVELOPER_COMMENT
                and not request.user.addonuser_set.filter(
                    addon=thread.addon).exists()):
            # Developer comment only for developers.
            return Response('Only developers can make developer comments',
                            status=status.HTTP_403_FORBIDDEN)
        elif (note_type == comm.REVIEWER_COMMENT
              and not acl.check_reviewer(request)):
            # Reviewer comment only for reviewers.
            return Response('Only reviewers can make reviewer comments',
                            status=status.HTTP_403_FORBIDDEN)

        # Create notes.
        thread, note = create_comm_note(thread.addon,
                                        thread.version,
                                        self.request.user,
                                        form.cleaned_data['body'],
                                        note_type=note_type)

        return Response(NoteSerializer(note, context={
            'request': request
        }).data,
                        status=status.HTTP_201_CREATED)
Пример #32
0
    def test_create_thread(self):
        # Default permissions.
        thread, note = create_comm_note(
            self.app, self.app.current_version, self.user, "huehue", note_type=comm.APPROVAL
        )

        # Check Thread.
        eq_(thread.webapp, self.app)
        eq_(thread.version, self.app.current_version)
        expected = {
            "public": False,
            "developer": True,
            "reviewer": True,
            "senior_reviewer": True,
            "mozilla_contact": True,
            "staff": True,
        }
        for perm, has_perm in expected.items():
            eq_(getattr(thread, "read_permission_%s" % perm), has_perm, perm)

        # Check Note.
        eq_(note.thread, thread)
        eq_(note.author, self.user)
        eq_(note.body, "huehue")
        eq_(note.note_type, comm.APPROVAL)

        # Check CC.
        eq_(thread.thread_cc.count(), 2)
        assert thread.thread_cc.filter(user=self.contact).exists()
        assert thread.thread_cc.filter(user=self.user).exists()
Пример #33
0
 def _create(self, note_type, author=None):
     author = author or self.reviewer
     return create_comm_note(self.extension,
                             self.extension.latest_version,
                             author,
                             'Test Comment',
                             note_type=note_type)
Пример #34
0
    def create(self, request, *args, **kwargs):
        if not waffle.switch_is_active('comm-dashboard'):
            return Response(status=status.HTTP_403_FORBIDDEN)

        thread = get_object_or_404(CommunicationThread, id=kwargs['thread_id'])

        # Validate note.
        form = forms.CreateCommNoteForm(request.DATA)
        if not form.is_valid():
            return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)
        note_type = form.cleaned_data['note_type']

        if (note_type == comm.DEVELOPER_COMMENT and not
            request.user.addonuser_set.filter(
                addon=thread.addon).exists()):
            # Developer comment only for developers.
            return Response('Only developers can make developer comments',
                            status=status.HTTP_403_FORBIDDEN)
        elif (note_type == comm.REVIEWER_COMMENT and not
              acl.check_reviewer(request)):
            # Reviewer comment only for reviewers.
            return Response('Only reviewers can make reviewer comments',
                            status=status.HTTP_403_FORBIDDEN)

        # Create notes.
        thread, note = create_comm_note(
            thread.addon, thread.version, self.request.user,
            form.cleaned_data['body'], note_type=note_type)

        return Response(
            NoteSerializer(note, context={'request': request}).data,
            status=status.HTTP_201_CREATED)
Пример #35
0
 def test_create_note_reviewer_type(self):
     for note_type in comm.REVIEWER_NOTE_TYPES:
         thread, note = create_comm_note(self.app,
                                         self.app.current_version,
                                         None,
                                         'huehue',
                                         note_type=note_type)
         eq_(note.read_permission_developer, False)
Пример #36
0
    def test_no_author(self):
        app = amo.tests.app_factory()
        thread, note = create_comm_note(app, app.current_version, None, 'hue')

        data = serializers.NoteSerializer(note, context={
            'request': amo.tests.req_factory_factory()
        }).data
        eq_(data['author_meta']['name'], 'Mozilla')
        eq_(data['author_meta']['gravatar_hash'], '')
Пример #37
0
    def save(self, *args, **kw):
        if self.data["notes"]:
            create_comm_note(
                self.instance,
                self.instance.versions.latest(),
                self.request.user,
                self.data["notes"],
                note_type=comm.SUBMISSION,
            )
        self.instance = super(AppDetailsBasicForm, self).save(commit=True)
        uses_flash = self.cleaned_data.get("flash")
        af = self.instance.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        for tag_text in self.cleaned_data["tags"]:
            Tag(tag_text=tag_text).save_tag(self.instance)

        return self.instance
Пример #38
0
    def test_no_author(self):
        app = app_factory()
        thread, note = create_comm_note(app, app.current_version, None, 'hue')

        data = serializers.NoteSerializer(note,
                                          context={
                                              'request': req_factory_factory()
                                          }).data
        eq_(data['author_meta']['name'], 'Mozilla')
        eq_(data['author_meta']['gravatar_hash'], '')
Пример #39
0
    def test_author(self):
        app = app_factory()
        user = user_factory(display_name='Bob')
        thread, note = create_comm_note(app, app.current_version, user, 'hue')

        data = serializers.NoteSerializer(note, context={
            'request': req_factory_factory()
        }).data
        eq_(data['author_meta']['name'], 'Bob')
        ok_(data['author_meta']['gravatar_hash'])
Пример #40
0
    def test_author(self):
        app = amo.tests.app_factory()
        user = amo.tests.user_factory()
        thread, note = create_comm_note(app, app.current_version, user, 'hue')

        data = serializers.NoteSerializer(note, context={
            'request': amo.tests.req_factory_factory()
        }).data
        eq_(data['author_meta']['name'], user.username)
        ok_(data['author_meta']['gravatar_hash'])
Пример #41
0
def app_summary(request, addon_id):
    app = get_object_or_404(Webapp.with_deleted, pk=addon_id)

    if "prioritize" in request.POST and not app.priority_review:
        app.update(priority_review=True)
        msg = u"Priority Review Requested"
        # Create notes and log entries.
        create_comm_note(app, app.latest_version, request.amo_user, msg, note_type=comm.NO_ACTION)
        amo.log(
            amo.LOG.PRIORITY_REVIEW_REQUESTED,
            app,
            app.latest_version,
            created=datetime.now(),
            details={"comments": msg},
        )

    authors = app.authors.filter(addonuser__role__in=(amo.AUTHOR_ROLE_DEV, amo.AUTHOR_ROLE_OWNER)).order_by(
        "display_name"
    )

    if app.premium and app.premium.price:
        price = app.premium.price
    else:
        price = None

    purchases, refunds = _app_purchases_and_refunds(app)
    provider_portals = get_payment_provider_portals(app=app)

    return render(
        request,
        "lookup/app_summary.html",
        {
            "abuse_reports": app.abuse_reports.count(),
            "app": app,
            "authors": authors,
            "downloads": _app_downloads(app),
            "purchases": purchases,
            "refunds": refunds,
            "price": price,
            "provider_portals": provider_portals,
        },
    )
Пример #42
0
    def test_create_note_existing_thread(self):
        # Initial note.
        thread, note = create_comm_note(self.app, self.app.current_version,
                                        self.user, 'huehue')

        # Second note from contact.
        thread, reply = create_comm_note(self.app,
                                         self.app.current_version,
                                         self.contact,
                                         'euheuh!',
                                         note_type=comm.REJECTION)

        # Third person joins thread.
        thread, last_word = create_comm_note(self.app,
                                             self.app.current_version,
                                             user_factory(),
                                             'euheuh!',
                                             note_type=comm.MORE_INFO_REQUIRED)

        eq_(thread.thread_cc.count(), 3)
Пример #43
0
    def test_author(self):
        app = app_factory()
        user = user_factory(display_name='Bob')
        thread, note = create_comm_note(app, app.current_version, user, 'hue')

        data = serializers.NoteSerializer(note,
                                          context={
                                              'request': req_factory_factory()
                                          }).data
        eq_(data['author_meta']['name'], 'Bob')
        ok_(data['author_meta']['gravatar_hash'])
Пример #44
0
    def test_custom_perms(self):
        thread, note = create_comm_note(
            self.app, self.app.current_version, self.user, 'escalatedquickly',
            note_type=comm.ESCALATION, perms={'developer': False,
                                              'staff': True})

        expected = {
            'public': False, 'developer': False, 'reviewer': True,
            'senior_reviewer': True, 'mozilla_contact': True, 'staff': True}
        for perm, has_perm in expected.items():
            eq_(getattr(thread, 'read_permission_%s' % perm), has_perm, perm)
Пример #45
0
    def create(self, request, *args, **kwargs):
        upload_pk = request.data.get('validation_id', '')
        if not upload_pk:
            raise exceptions.ParseError(_('No validation_id specified.'))

        try:
            upload = FileUpload.objects.get(pk=upload_pk, user=request.user)
        except FileUpload.DoesNotExist:
            raise Http404(_('No such upload.'))
        if not upload.valid:
            raise exceptions.ParseError(
                _('The specified upload has not passed validation.'))

        if 'extension_pk' in self.kwargs:
            # We are creating a new ExtensionVersion.
            params = {'parent': self.get_extension_object()}
        else:
            # We are creating a new Extension.
            params = {'user': request.user}

        # self.model.from_upload() will raise ParseError if appropriate.
        obj = self.model.from_upload(upload, **params)
        log.info('%s created: %s' % (self.model, self.model.pk))

        # TODO: change create_comm_note to just take a version.
        if 'extension_pk' in self.kwargs:
            create_comm_note(obj.extension,
                             obj,
                             request.user,
                             request.data.get('message', ''),
                             note_type=comm.SUBMISSION)
        else:
            create_comm_note(obj,
                             obj.latest_version,
                             request.user,
                             request.data.get('message', ''),
                             note_type=comm.SUBMISSION)

        serializer = self.get_serializer(obj)

        return Response(serializer.data, status=status.HTTP_201_CREATED)
Пример #46
0
    def _create_comm_note(self, note_type):
        # Permissions default to developers + reviewers + Mozilla contacts.
        # For escalation/comment, exclude the developer from the conversation.
        perm_overrides = {
            comm.ESCALATION: {'developer': False},
            comm.REVIEWER_COMMENT: {'developer': False},
        }

        self.comm_thread, self.comm_note = create_comm_note(
            self.addon, self.version, self.request.amo_user,
            self.data['comments'], note_type=note_type,
            perms=perm_overrides.get(note_type))
Пример #47
0
def escalate_app(app, version, user, msg, email_template, log_type):
    # Add to escalation queue
    EscalationQueue.objects.get_or_create(addon=app)

    # Create comm note
    create_comm_note(app, version, user, msg,
                     note_type=comm.ACTION_MAP(log_type))

    # Log action
    amo.log(log_type, app, version, created=datetime.now(),
            details={'comments': msg})
    log.info(u'[app:%s] escalated - %s' % (app.name, msg))

    # Special senior reviewer email.
    if not waffle.switch_is_active('comm-dashboard'):
        context = {'name': app.name,
                   'review_url': absolutify(reverse('reviewers.apps.review',
                                                    args=[app.app_slug])),
                   'SITE_URL': settings.SITE_URL}
        send_reviewer_mail(u'%s: %s' % (msg, app.name), email_template, context,
                           [settings.MKT_SENIOR_EDITORS_EMAIL])
Пример #48
0
    def test_author(self):
        app = amo.tests.app_factory()
        user = amo.tests.user_factory()
        thread, note = create_comm_note(app, app.current_version, user, 'hue')

        data = serializers.NoteSerializer(note,
                                          context={
                                              'request':
                                              amo.tests.req_factory_factory()
                                          }).data
        eq_(data['author_meta']['name'], user.username)
        ok_(data['author_meta']['gravatar_hash'])
Пример #49
0
def version_edit(request, addon_id, addon, version_id):
    show_features = addon.is_packaged
    formdata = request.POST if request.method == 'POST' else None
    version = get_object_or_404(Version, pk=version_id, addon=addon)
    version.addon = addon  # Avoid extra useless query.
    form = AppVersionForm(formdata, instance=version)
    all_forms = [form]

    if show_features:
        appfeatures = version.features
        appfeatures_form = AppFeaturesForm(request.POST or None,
                                           instance=appfeatures)
        all_forms.append(appfeatures_form)

    if request.method == 'POST' and all(f.is_valid() for f in all_forms):
        [f.save() for f in all_forms]

        if f.data.get('approvalnotes'):
            create_comm_note(
                addon,
                version,
                request.user,
                f.data['approvalnotes'],
                note_type=comm.DEVELOPER_VERSION_NOTE_FOR_REVIEWER)

        messages.success(request, _('Version successfully edited.'))
        return redirect(addon.get_dev_url('versions'))

    context = {'addon': addon, 'version': version, 'form': form}

    if show_features:
        context.update({
            'appfeatures_form':
            appfeatures_form,
            'appfeatures':
            appfeatures,
            'feature_list': [unicode(f) for f in appfeatures.to_list()]
        })

    return render(request, 'developers/apps/version_edit.html', context)
Пример #50
0
def save_from_email_reply(reply_text):
    from mkt.comm.utils import create_comm_note

    log.debug("Saving from email reply")

    parser = CommEmailParser(reply_text)
    if hasattr(parser, 'decode_error'):
        return False

    uuid = parser.get_uuid()

    if not uuid:
        return False
    try:
        tok = CommunicationThreadToken.objects.get(uuid=uuid)
    except CommunicationThreadToken.DoesNotExist:
        log.error('An email was skipped with non-existing uuid %s.' % uuid)
        return False

    thread = tok.thread
    if user_has_perm_thread(thread, tok.user) and tok.is_valid():
        # Deduce an appropriate note type.
        note_type = comm.NO_ACTION

        # grep: comm-content-type.
        if (thread.obj.__class__ == Webapp
                and tok.user.addonuser_set.filter(addon=thread.obj).exists()):
            note_type = comm.DEVELOPER_COMMENT
        elif (thread.obj.__class__ == Extension
              and tok.user.extension_set.filter(id=thread.obj.id).exists()):
            note_type = comm.DEVELOPER_COMMENT
        elif (acl.action_allowed_user(tok.user, 'Apps', 'Review')
              or acl.action_allowed_user(tok.user, 'ContentTools',
                                         'AddonReview')):
            note_type = comm.REVIEWER_PUBLIC_COMMENT

        t, note = create_comm_note(tok.thread.obj,
                                   tok.thread.version,
                                   tok.user,
                                   parser.get_body(),
                                   note_type=note_type)
        log.info('A new note has been created (from %s using tokenid %s).' %
                 (tok.user.id, uuid))
        return note
    elif tok.is_valid():
        log.error('%s did not have perms to reply to comm email thread %s.' %
                  (tok.user.email, tok.thread.id))
    else:
        log.error('%s tried to use an invalid comm token for thread %s.' %
                  (tok.user.email, tok.thread.id))

    return False
Пример #51
0
    def create(self, request, *args, **kwargs):
        upload_pk = request.DATA.get('validation_id', '')
        if not upload_pk:
            raise exceptions.ParseError(_('No validation_id specified.'))

        if not request.user.is_authenticated():
            raise exceptions.PermissionDenied(
                _('You need to be authenticated to perform this action.'))

        try:
            upload = FileUpload.objects.get(pk=upload_pk, user=request.user)
        except FileUpload.DoesNotExist:
            raise Http404(_('No such upload.'))
        if not upload.valid:
            raise exceptions.ParseError(
                _('The specified upload has not passed validation.'))

        if 'extension_pk' in self.kwargs:
            # We are creating a new ExtensionVersion.
            params = {'parent': self.get_extension_object()}
        else:
            # We are creating a new Extension
            params = {'user': request.user}

        # self.model.from_upload() will raise ParseError if appropriate.
        obj = self.model.from_upload(upload, **params)
        log.info('%s created: %s' % (self.model, self.model.pk))

        # TODO: change create_comm_note to just take a version.
        if 'extension_pk' in self.kwargs:
            create_comm_note(obj.extension, obj, request.user, '',
                             note_type=comm.SUBMISSION)
        else:
            create_comm_note(obj, obj.latest_version, request.user, '',
                             note_type=comm.SUBMISSION)

        serializer = self.get_serializer(obj)

        return Response(serializer.data, status=status.HTTP_201_CREATED)
Пример #52
0
def version_edit(request, addon_id, addon, version_id):
    show_features = addon.is_packaged
    formdata = request.POST if request.method == 'POST' else None
    version = get_object_or_404(Version, pk=version_id, addon=addon)
    version.addon = addon  # Avoid extra useless query.
    form = AppVersionForm(formdata, instance=version)
    all_forms = [form]

    if show_features:
        appfeatures = version.features
        appfeatures_form = AppFeaturesForm(request.POST or None,
                                           instance=appfeatures)
        all_forms.append(appfeatures_form)

    if request.method == 'POST' and all(f.is_valid() for f in all_forms):
        [f.save() for f in all_forms]

        if f.data.get('approvalnotes'):
            create_comm_note(addon, version, request.user,
                             f.data['approvalnotes'],
                             note_type=comm.REVIEWER_COMMENT)

        messages.success(request, _('Version successfully edited.'))
        return redirect(addon.get_dev_url('versions'))

    context = {
        'addon': addon,
        'version': version,
        'form': form
    }

    if show_features:
        context.update({
            'appfeatures_form': appfeatures_form,
            'appfeatures': appfeatures,
            'feature_list': [unicode(f) for f in appfeatures.to_list()]
        })

    return render(request, 'developers/apps/version_edit.html', context)
Пример #53
0
    def test_create_note_existing_thread(self):
        # Initial note.
        thread, note = create_comm_note(
            self.app, self.app.current_version, self.user, 'huehue')

        # Second note from contact.
        thread, reply = create_comm_note(
            self.app, self.app.current_version, self.contact, 'euheuh!',
            note_type=comm.REJECTION)

        # Mark read by author.
        eq_(reply.read_by_users.count(), 1)

        # Third person joins thread.
        thread, last_word = create_comm_note(
            self.app, self.app.current_version, user_factory(), 'euheuh!',
            note_type=comm.MORE_INFO_REQUIRED)

        # More checking that joining a thread marks all old notes as read.
        eq_(thread.thread_cc.count(), 3)
        eq_(note.read_by_users.count(), 3)
        eq_(last_word.read_by_users.count(), 1)
Пример #54
0
def save_from_email_reply(reply_text):
    from mkt.comm.utils import create_comm_note

    log.debug("Saving from email reply")

    parser = CommEmailParser(reply_text)
    if hasattr(parser, 'decode_error'):
        return False

    uuid = parser.get_uuid()

    if not uuid:
        return False
    try:
        tok = CommunicationThreadToken.objects.get(uuid=uuid)
    except CommunicationThreadToken.DoesNotExist:
        log.error('An email was skipped with non-existing uuid %s.' % uuid)
        return False

    thread = tok.thread
    if user_has_perm_thread(thread, tok.user) and tok.is_valid():
        # Deduce an appropriate note type.
        note_type = comm.NO_ACTION

        # grep: comm-content-type.
        if (thread.obj.__class__ == Webapp and
                tok.user.addonuser_set.filter(addon=thread.obj).exists()):
            note_type = comm.DEVELOPER_COMMENT
        elif (thread.obj.__class__ == Extension and
                tok.user.extension_set.filter(id=thread.obj.id).exists()):
            note_type = comm.DEVELOPER_COMMENT
        elif (acl.action_allowed_user(tok.user, 'Apps', 'Review') or
              acl.action_allowed_user(tok.user, 'ContentTools',
                                      'AddonReview')):
            note_type = comm.REVIEWER_COMMENT

        t, note = create_comm_note(tok.thread.obj, tok.thread.version,
                                   tok.user, parser.get_body(),
                                   note_type=note_type)
        log.info('A new note has been created (from %s using tokenid %s).'
                 % (tok.user.id, uuid))
        return note
    elif tok.is_valid():
        log.error('%s did not have perms to reply to comm email thread %s.'
                  % (tok.user.email, tok.thread.id))
    else:
        log.error('%s tried to use an invalid comm token for thread %s.'
                  % (tok.user.email, tok.thread.id))

    return False