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])
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})
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)
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)
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)
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})
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)
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})
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)
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)
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
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))
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
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))
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, })
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)
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)
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)
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)
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)
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)
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)
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))
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)
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)
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)
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()
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)
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)
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)
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'], '')
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
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'], '')
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'])
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'])
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, }, )
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)
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)
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)
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))
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])
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)
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
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)
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)
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)
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