def save(self): u = super(UserEditForm, self).save(commit=False) data = self.cleaned_data photo = data['photo'] if photo: u.picture_type = 'image/png' tmp_destination = u.picture_path + '__unconverted' if not os.path.exists(u.picture_dir): os.makedirs(u.picture_dir) fh = open(tmp_destination, 'w') for chunk in photo.chunks(): fh.write(chunk) fh.close() resize_photo.delay(tmp_destination, u.picture_path, set_modified_on=[u]) for i, n in email.APP_NOTIFICATIONS_BY_ID.iteritems(): enabled = n.mandatory or (str(i) in data['notifications']) UserNotification.update_or_create(user=u, notification_id=i, update={'enabled': enabled}) log.debug(u'User (%s) updated their profile' % u) u.save() return u
def save(self, commit=False): from .tasks import create_persona_preview_image, save_persona_image # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addon = super(NewPersonaForm, self).save(commit=False) addon.status = amo.STATUS_UNREVIEWED addon.type = amo.ADDON_PERSONA addon.save() addon._current_version = Version.objects.create(addon=addon, version='0') addon.save() amo.log(amo.LOG.CREATE_ADDON, addon) log.debug('New persona %r uploaded' % addon) data = self.cleaned_data header = data['header_hash'] footer = data['footer_hash'] header = os.path.join(settings.TMP_PATH, 'persona_header', header) footer = os.path.join(settings.TMP_PATH, 'persona_footer', footer) dst = os.path.join(settings.PERSONAS_PATH, str(addon.id)) # Save header, footer, and preview images. save_persona_image(src=header, dst=dst, img_basename='header.jpg') save_persona_image(src=footer, dst=dst, img_basename='footer.jpg') create_persona_preview_image(src=header, dst=dst, img_basename='preview.jpg', set_modified_on=[addon]) # Save user info. user = self.request.amo_user AddonUser(addon=addon, user=user).save() p = Persona() p.persona_id = 0 p.addon = addon p.header = 'header.jpg' p.footer = 'footer.jpg' if data['accentcolor']: p.accentcolor = data['accentcolor'].lstrip('#') if data['textcolor']: p.textcolor = data['textcolor'].lstrip('#') p.license_id = data['license'] p.submit = datetime.now() p.author = user.name p.display_username = user.username p.save() # Save tags. for t in data['tags']: Tag(tag_text=t).save_tag(addon) # Save categories. tb_c = Category.objects.get(application=amo.THUNDERBIRD.id, name__id=data['category'].name_id) AddonCategory(addon=addon, category=data['category']).save() AddonCategory(addon=addon, category=tb_c).save() return addon
def revision_add_attachment(request, pk): """Add attachment, download if necessary """ revision = get_object_or_404(PackageRevision, pk=pk) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add attachment to package (%s) by " "non-owner (%s)" % (revision.package, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) url = request.POST.get('url', None) filename = request.POST.get('filename', None) log.debug(filename) if not filename or filename == "": log.error('Trying to create an attachment without name') return HttpResponseForbidden('Path not found.') content = '' if url: # validate url field = URLField(verify_exists=True) try: url = field.clean(url) except ValidationError, err: log.debug('Invalid url provided (%s)\n%s' % (url, '\n'.join(err.messages))) return HttpResponseForbidden(("Loading attachment failed<br/>" "%s") % '<br/>'.join(err.messages)) except Exception, err: return HttpResponseForbidden(str(err))
def collection_subscribers(): """ Collection weekly and monthly subscriber counts. """ log.debug('Starting collection subscriber update...') cursor = connection.cursor() cursor.execute(""" UPDATE collections SET weekly_subscribers = 0, monthly_subscribers = 0 """) cursor.execute(""" UPDATE collections AS c INNER JOIN ( SELECT COUNT(collection_id) AS count, collection_id FROM collection_subscriptions WHERE created >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY collection_id ) AS weekly ON (c.id = weekly.collection_id) INNER JOIN ( SELECT COUNT(collection_id) AS count, collection_id FROM collection_subscriptions WHERE created >= DATE_SUB(CURDATE(), INTERVAL 31 DAY) GROUP BY collection_id ) AS monthly ON (c.id = monthly.collection_id) SET c.weekly_subscribers = weekly.count, c.monthly_subscribers = monthly.count """) transaction.commit_unless_managed()
def prepare_pay(request, addon): """Prepare a BlueVia JWT to pass into navigator.pay()""" amount, currency, uuid_, contrib_for = start_purchase(request, addon) log.debug('Storing contrib for uuid: %s' % uuid_) Contribution.objects.create(addon_id=addon.id, amount=amount, source=request.REQUEST.get('src', ''), source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=None, user=request.amo_user, price_tier=addon.premium.price, client_data=ClientData.get_or_create(request)) data = {'amount': str(amount), 'currency': currency, 'app_name': unicode(addon.name), 'app_description': unicode(addon.description), 'postback_url': absolutify(reverse('bluevia.postback')), 'chargeback_url': absolutify(reverse('bluevia.chargeback')), 'seller': addon.pk, 'product_data': urlencode({'contrib_uuid': uuid_, 'addon_id': addon.pk}), 'typ': 'tu.com/payments/inapp/v1', 'aud': 'tu.com', 'memo': contrib_for} if waffle.flag_is_active(request, 'solitude-payments'): bluevia_jwt = client.prepare_bluevia_pay(data) else: bluevia_jwt = prepare_bluevia_pay(data) return {'blueviaJWT': bluevia_jwt, 'contribStatusURL': reverse('bluevia.pay_status', args=[addon.app_slug, uuid_])}
def activity_log_scrubber(): """ Scans activity log for REMOVE_FROM_COLLECTION and ADD_TO_COLLECTION, looks for collections in arguments and checks whether collection is listed. """ items = ActivityLog.objects.filter( action__in=[amo.LOG.ADD_TO_COLLECTION.id, amo.LOG.REMOVE_FROM_COLLECTION.id]) ids = [] count = 0 # ~127K for item in items: count += 1 for arg in item.arguments: if isinstance(arg, Collection) and not arg.listed: log.debug('Flagging %s.' % item) log.debug('%d items seen.' % count) ids.append(item.id) log.info('Deleting %d items.' % len(ids)) for chunk in chunked(ids, 100): _activity_log_scrubber.delay(chunk)
def reply(request, addon, review_id): is_admin = acl.action_allowed(request, 'Addons', 'Edit') is_author = acl.check_addon_ownership(request, addon, dev=True) if not (is_admin or is_author): return http.HttpResponseForbidden() review = get_object_or_404(Review.objects, pk=review_id, addon=addon) form = forms.ReviewReplyForm(request.POST or None) if request.method == 'POST' and form.is_valid(): d = dict(reply_to=review, addon=addon, defaults=dict(user=request.amo_user)) reply, new = Review.objects.get_or_create(**d) for key, val in _review_details(request, addon, form).items(): setattr(reply, key, val) reply.save() action = 'New' if new else 'Edited' log.debug('%s reply to %s: %s' % (action, review_id, reply.id)) if new: reply_url = shared_url('reviews.detail', addon, review.id, add_prefix=False) data = {'name': addon.name, 'reply_title': reply.title, 'reply': reply.body, 'reply_url': absolutify(reply_url)} emails = [review.user.email] sub = u'Mozilla Add-on Developer Reply: %s' % addon.name send_mail('reviews/emails/reply_review.ltxt', sub, emails, Context(data), 'reply') return redirect(shared_url('reviews.detail', addon, review_id)) ctx = dict(review=review, form=form, addon=addon) return jingo.render(request, 'reviews/reply.html', ctx)
def cleanup_extracted_file(): log.info('Removing extracted files for file viewer.') root = os.path.join(settings.TMP_PATH, 'file_viewer') # Local storage uses local time for file modification. S3 uses UTC time. now = datetime.utcnow if storage_is_remote() else datetime.now for path in private_storage.listdir(root)[0]: full = os.path.join(root, path) age = now() - private_storage.modified_time( os.path.join(full, 'manifest.webapp')) if age.total_seconds() > (60 * 60): log.debug('Removing extracted files: %s, %dsecs old.' % (full, age.total_seconds())) for subroot, dirs, files in walk_storage(full): for f in files: private_storage.delete(os.path.join(subroot, f)) # Nuke out the file and diff caches when the file gets removed. id = os.path.basename(path) try: int(id) except ValueError: continue key = hashlib.md5() key.update(str(id)) cache.delete('%s:memoize:%s:%s' % (settings.CACHE_PREFIX, 'file-viewer', key.hexdigest()))
def save(self, log_for_developer=True): u = super(UserEditForm, self).save(commit=False) data = self.cleaned_data photo = data['photo'] if photo: u.picture_type = 'image/png' tmp_destination = u.picture_path + '__unconverted' with storage.open(tmp_destination, 'wb') as fh: for chunk in photo.chunks(): fh.write(chunk) tasks.resize_photo.delay(tmp_destination, u.picture_path, set_modified_on=[u]) if data['password']: u.set_password(data['password']) log_cef('Password Changed', 5, self.request, username=u.username, signature='PASSWORDCHANGED', msg='User changed password') if log_for_developer: amo.log(amo.LOG.CHANGE_PASSWORD) log.info(u'User (%s) changed their password' % u) for (i, n) in email.NOTIFICATIONS_BY_ID.items(): enabled = n.mandatory or (str(i) in data['notifications']) UserNotification.update_or_create(user=u, notification_id=i, update={'enabled': enabled}) log.debug(u'User (%s) updated their profile' % u) u.save() return u
def arguments(self): try: # d is a structure: # ``d = [{'addons.addon':12}, {'addons.addon':1}, ... ]`` d = json.loads(self._arguments) except: log.debug('unserializing data from addon_log failed: %s' % self.id) return None objs = [] for item in d: # item has only one element. model_name, pk = item.items()[0] if model_name in ('str', 'int', 'null'): objs.append(pk) else: (app_label, model_name) = model_name.split('.') model = models.loading.get_model(app_label, model_name) # Cope with soft deleted models. if hasattr(model, 'with_deleted'): objs.extend(model.with_deleted.filter(pk=pk)) else: objs.extend(model.objects.filter(pk=pk)) return objs
def upload_attachment(request, revision_id): """ Upload new attachment to the PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) log.debug(revision) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to upload attachment to package (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) f = request.FILES.get('upload_attachment') filename = request.META.get('HTTP_X_FILE_NAME') if not f: log_msg = 'Path not found: %s, revision: %s.' % ( filename, revision_id) log.error(log_msg) return HttpResponseServerError('Path not found.') content = f.read() # try to force UTF-8 code, on error continue with original data try: content = unicode(content, 'utf-8') except: pass try: attachment = revision.attachment_create_by_filename( request.user, filename, content) except ValidationError, e: return HttpResponseForbidden( 'Validation errors.\n%s' % parse_validation_messages(e))
def extract_lang(project, locale, path, entities=False): """Extract .lang file with path and save or update in DB.""" lang = parse_lang(path) relative_path = get_relative_path(path, locale) resource, created = Resource.objects.get_or_create( project=project, path=relative_path, format='lang') if entities: for order, (key, value) in enumerate(lang): save_entity( resource=resource, string=key, comment=value[1], order=order) update_entity_count(resource) else: for key, value in lang: if key != value[2] or '{ok}' in value[3]: try: e = Entity.objects.get( resource=resource, string__iexact=key) save_translation( entity=e, locale=locale, string=value[2]) except Entity.DoesNotExist: continue update_stats(resource, locale) log.debug("[" + locale.code + "]: " + path + " saved to DB.")
def add(request, addon, template=None): if addon.has_author(request.user): raise PermissionDenied form = forms.ReviewForm(request.POST or None) if (request.method == 'POST' and form.is_valid() and not request.POST.get('detailed')): details = _review_details(request, addon, form) review = Review.objects.create(**details) if 'flag' in form.cleaned_data and form.cleaned_data['flag']: rf = ReviewFlag(review=review, user_id=request.user.id, flag=ReviewFlag.OTHER, note='URLs') rf.save() amo.log(amo.LOG.ADD_REVIEW, addon, review) log.debug('New review: %s' % review.id) reply_url = helpers.url('addons.reviews.reply', addon.slug, review.id, add_prefix=False) data = {'name': addon.name, 'rating': '%s out of 5 stars' % details['rating'], 'review': details['body'], 'reply_url': helpers.absolutify(reply_url)} emails = [a.email for a in addon.authors.all()] send_mail('reviews/emails/add_review.ltxt', u'Mozilla Add-on User Review: %s' % addon.name, emails, Context(data), 'new_review') return redirect(helpers.url('addons.reviews.list', addon.slug)) return render(request, template, dict(addon=addon, form=form))
def commit(self, path=None, message=None, user=None): log.debug("Git: Commit to repository.") path = path or self.path message = message or self.message user = user or self.user author = self.get_author(user) # Add add = ["git", "add", "-A"] execute(add, path) # Commit commit = ["git", "commit", "-m", message, "--author", author] code, output, error = execute(commit, path) if code != 0 and len(error): raise CommitToRepositoryException(unicode(error)) # Push push = ["git", "push"] code, output, error = execute(push, path) if code != 0: raise CommitToRepositoryException(unicode(error)) if 'Everything up-to-date' in error: self.nothing_to_commit() log.info(message)
def dump_po(project, locale): """Update .po (gettext) files from database.""" locale_paths = get_locale_paths(project, locale) for path in locale_paths: po = polib.pofile(path) date = datetime.datetime(1, 1, 1) newest = Translation() relative_path = get_relative_path(path, locale) resource = Resource.objects.filter(project=project, path=relative_path) entities = Entity.objects.filter(resource=resource, obsolete=False) for entity in entities: entry = po.find(polib.unescape(smart_text(entity.string))) if entry: if not entry.msgid_plural: translation = get_translation(entity=entity, locale=locale) if translation.string != '': entry.msgstr = polib.unescape(translation.string) if translation.date > date: date = translation.date newest = translation if ('fuzzy' in entry.flags and not translation.fuzzy): entry.flags.remove('fuzzy') else: for i in range(0, 6): if i < (locale.nplurals or 1): translation = get_translation( entity=entity, locale=locale, plural_form=i) if translation.string != '': entry.msgstr_plural[unicode(i)] = \ polib.unescape(translation.string) if translation.date > date: date = translation.date newest = translation if ('fuzzy' in entry.flags and not translation.fuzzy): entry.flags.remove('fuzzy') # Remove obsolete plural forms if exist else: if unicode(i) in entry.msgstr_plural: del entry.msgstr_plural[unicode(i)] # Update PO metadata if newest.id: po.metadata['PO-Revision-Date'] = newest.date if newest.user: po.metadata['Last-Translator'] = '%s <%s>' \ % (newest.user.first_name, newest.user.email) po.metadata['Language'] = locale.code po.metadata['X-Generator'] = 'Pontoon' if locale.nplurals: po.metadata['Plural-Forms'] = 'nplurals=%s; plural=%s;' \ % (str(locale.nplurals), locale.plural_rule) po.save() log.debug("File updated: " + path)
def start_purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # L10n: {0} is the addon name. contrib_for = (_(u'Firefox Marketplace purchase of {0}') .format(addon.name)) # Default is USD. amount, currency = addon.premium.get_price(), 'USD' # If tier is specified, then let's look it up. if waffle.switch_is_active('currencies'): form = PriceCurrencyForm(data=request.POST, addon=addon) if form.is_valid(): tier = form.get_tier() if tier: amount, currency = tier.price, tier.currency if waffle.flag_is_active(request, 'solitude-payments'): # TODO(solitude): when the migration of data is completed, we # will be able to remove this. Seller data is populated in solitude # on submission or devhub changes. If those don't occur, you won't be # able to sell at all. client.create_seller_for_pay(addon) return amount, currency, uuid_, contrib_for
def save(self, log_for_developer=True): u = super(UserEditForm, self).save(commit=False) data = self.cleaned_data photo = data['photo'] if photo: u.picture_type = 'image/png' tmp_destination = u.picture_path + '__unconverted' if not os.path.exists(u.picture_dir): os.makedirs(u.picture_dir) fh = open(tmp_destination, 'w') for chunk in photo.chunks(): fh.write(chunk) fh.close() tasks.resize_photo.delay(tmp_destination, u.picture_path, set_modified_on=[u]) if data['password']: u.set_password(data['password']) if log_for_developer: amo.log(amo.LOG.CHANGE_PASSWORD) log.info(u'User (%s) changed their password' % u) for (i, n) in email.NOTIFICATIONS_BY_ID.items(): enabled = n.mandatory or (str(i) in data['notifications']) UserNotification.update_or_create(user=u, notification_id=i, update={'enabled': enabled}) log.debug(u'User (%s) updated their profile' % u) u.save() return u
def reply(request, addon, review_id): is_admin = acl.action_allowed(request, 'Addons', 'Edit') is_author = acl.check_addon_ownership(request, addon, dev=True) if not (is_admin or is_author): raise PermissionDenied review = get_object_or_404(Review.objects, pk=review_id, addon=addon) form = ReviewReplyForm(request.POST or None) if form.is_valid(): d = dict(reply_to=review, addon=addon, defaults=dict(user=request.amo_user)) reply, new = Review.objects.get_or_create(**d) for k, v in _review_details(request, addon, form).items(): setattr(reply, k, v) reply.save() action = 'New' if new else 'Edited' if new: amo.log(amo.LOG.ADD_REVIEW, addon, reply) else: amo.log(amo.LOG.EDIT_REVIEW, addon, reply) log.debug('%s reply to %s: %s' % (action, review_id, reply.id)) messages.success(request, _('Your reply was successfully added.') if new else _('Your reply was successfully updated.')) return http.HttpResponse()
def handle(self, *args, **options): day = options["date"] if not day: raise CommandError("You must specify a --date parameter in the " " YYYY-MM-DD format.") filename = options["filename"] if filename is None: filename = day sep = options["separator"] limit = options["limit"] with_updates = options["with_updates"] with_downloads = options["with_downloads"] if not with_updates and not with_downloads: raise CommandError("Please specify at least one of --with-updates " "or --with-downloads.") with ClevererConnection( host="peach-gw.peach.metrics.scl3.mozilla.com", port=10000, user="******", password="", authMechanism="PLAIN", ) as conn: num_reqs = 0 with conn.cursor() as cur: start = datetime.now() # Measure the time to run the script. if with_downloads: num_reqs += self.process_downloads(cur, day, filename, sep=sep, limit=limit) if with_updates: num_reqs += self.process_updates(cur, day, filename, sep=sep, limit=limit) total_time = (datetime.now() - start).total_seconds() log.info("Stored a total of %s requests" % num_reqs) log.debug("Total processing time: %s seconds" % total_time) log.debug("Time spent fetching data from hive over the network: %s" % fetch_time)
def pull(self, source=None, target=None): log.debug("Mercurial: Update repository.") source = source or self.source target = target or self.target # Undo local changes command = ["hg", "revert", "--all", "--no-backup"] execute(command, target) command = ["hg", "pull", "-u"] code, output, error = execute(command, target) if code == 0: log.debug("Mercurial: Repository at " + source + " updated.") else: log.debug("Mercurial: " + unicode(error)) log.debug("Mercurial: Clone instead.") command = ["hg", "clone", source, target] code, output, error = execute(command) if code == 0: log.debug("Mercurial: Repository at " + source + " cloned.") else: raise PullFromRepositoryException(unicode(error))
def obj_create(self, bundle, request=None, **kwargs): """ Handle POST requests to the resource. If the data validates, create a new Review from bundle data. """ form = ReviewForm(bundle.data) if not form.is_valid(): raise self.form_errors(form) app = self.get_app(bundle.data['app']) # Return 409 if the user has already reviewed this app. if self._meta.queryset.filter(addon=app, user=request.user).exists(): raise ImmediateHttpResponse(response=http.HttpConflict()) # Return 403 if the user is attempting to review their own app: if app.has_author(request.user): raise ImmediateHttpResponse(response=http.HttpForbidden()) # Return 403 if not a free app and the user hasn't purchased it. if app.is_premium() and not app.is_purchased(request.amo_user): raise ImmediateHttpResponse(response=http.HttpForbidden()) bundle.obj = Review.objects.create(**self._review_data(request, app, form)) amo.log(amo.LOG.ADD_REVIEW, app, bundle.obj) log.debug('[Review:%s] Created by user %s ' % (bundle.obj.id, request.user.id)) record_action('new-review', request, {'app-id': app.id}) return bundle
def _xpi_form_error(f, request): resp = rc.BAD_REQUEST error = ','.join([e[0] for e in f.errors.values()]) resp.write(': ' + _('Add-on did not validate: %s') % error) log.debug('Add-on did not validate (%s) for %s' % (error, request.amo_user)) return resp
def vouchify(): """Synchronizes LDAP vouch info into database. This queries LDAP for users who's corresponding ``UserProfile`` has ``is_vouched`` as ``False``. It then updates ``is_vouched`` and ``vouched_by`` with up-to-date data. """ users = UserProfile.objects.filter(is_vouched=False) for user in users: person = user.get_ldap_person() if person and 'mozilliansVouchedBy' in person[1]: user.is_vouched = True voucher = (person[1]['mozilliansVouchedBy'][0].split(',')[0] .split('=')[1]) by = larper.get_user_by_uid(voucher) if by: email = by[1]['mail'][0] try: user.vouched_by = (User.objects.get(email=email) .get_profile()) except User.DoesNotExist: log.warning('No matching user for %s' % email) except UserProfile.DoesNotExist: log.warning('No matching user_profile for %s' % email) user.save() log.info('Data copied for %s' % user.user.username) log.debug('%s is still unvouched... skipping' % user.user.username)
def inherit_nomination(sender, instance, **kw): """For new versions pending review, ensure nomination date is inherited from last nominated version. """ if kw.get("raw"): return addon = instance.addon if addon.type == amo.ADDON_WEBAPP and addon.is_packaged: # If prior version's file is pending, inherit nomination. Otherwise, # set nomination to now. last_ver = Version.objects.filter(addon=addon).exclude(pk=instance.pk).order_by("-nomination") if last_ver.exists() and last_ver[0].all_files[0].status == amo.STATUS_PENDING: instance.update(nomination=last_ver[0].nomination, _signal=False) log.debug("[Webapp:%s] Inheriting nomination from prior pending " "version" % addon.id) elif addon.status in amo.WEBAPPS_APPROVED_STATUSES and not instance.nomination: log.debug("[Webapp:%s] Setting nomination date to now for new " "version." % addon.id) instance.update(nomination=datetime.datetime.now(), _signal=False) else: if ( instance.nomination is None and addon.status in (amo.STATUS_NOMINATED, amo.STATUS_LITE_AND_NOMINATED) and not instance.is_beta ): last_ver = Version.objects.filter(addon=addon).exclude(nomination=None).order_by("-nomination") if last_ver.exists(): instance.update(nomination=last_ver[0].nomination, _signal=False)
def delete_photo(request): request.amo_user.update(picture_type='') delete_photo_task.delay(request.amo_user.picture_path) log.debug(u'User (%s) deleted photo' % request.amo_user) messages.success(request, _('Photo Deleted')) amo.log(amo.LOG.USER_EDITED) return http.HttpResponse()
def commit(self, path=None, message=None, user=None): log.debug("Mercurial: Commit to repository.") path = path or self.path message = message or self.message user = user or self.user author = self.get_author(user) # Add add = ["hg", "add"] execute(add, path) # Commit commit = ["hg", "commit", "-m", message, "-u", author] code, output, error = execute(commit, path) if code != 0 and len(error): raise CommitToRepositoryException(unicode(error)) # Push push = ["hg", "push"] code, output, error = execute(push, path) if code == 1 and 'no changes found' in output: self.nothing_to_commit() if code != 0 and len(error): raise CommitToRepositoryException(unicode(error)) log.info(message)
def add(request, addon, template=None): if addon.has_author(request.user): return http.HttpResponseForbidden() form = forms.ReviewForm(request.POST or None) if (request.method == 'POST' and form.is_valid() and not request.POST.get('detailed')): details = _review_details(request, addon, form) review = Review.objects.create(**details) amo.log(amo.LOG.ADD_REVIEW, addon, review) log.debug('New review: %s' % review.id) reply_url = shared_url('reviews.reply', addon, review.id, add_prefix=False) data = {'name': addon.name, 'rating': '%s out of 5 stars' % details['rating'], 'review': details['body'], 'reply_url': absolutify(reply_url)} emails = [a.email for a in addon.authors.all()] send_mail('reviews/emails/add_review.ltxt', u'Mozilla Add-on User Review: %s' % addon.name, emails, Context(data), 'new_review') # Update the ratings and counts for the add-on. addon_review_aggregates.delay(addon.id, using='default') return redirect(shared_url('reviews.list', addon)) return jingo.render(request, template, dict(addon=addon, form=form))
def pull(self, source=None, target=None): log.debug("Git: Update repository.") source = source or self.source target = target or self.target command = ["git", "fetch", "--all"] execute(command, target) # Undo local changes command = ["git", "reset", "--hard", "origin/master"] code, output, error = execute(command, target) if code == 0: log.debug("Git: Repository at " + source + " updated.") else: log.debug("Git: " + unicode(error)) log.debug("Git: Clone instead.") command = ["git", "clone", source, target] code, output, error = execute(command) if code == 0: log.debug("Git: Repository at " + source + " cloned.") else: raise PullFromRepositoryException(unicode(error))
def call_signing(file_obj, endpoint): """Get the jar signature and send it to the signing server to be signed.""" # We only want the (unique) temporary file name. with tempfile.NamedTemporaryFile() as temp_file: temp_filename = temp_file.name # Extract jar signature. jar = JarExtractor(path=storage.open(file_obj.file_path), outpath=temp_filename, omit_signature_sections=True, extra_newlines=True) log.debug(u'File signature contents: {0}'.format(jar.signatures)) log.debug(u'Calling signing service: {0}'.format(endpoint)) with statsd.timer('services.sign.addon'): response = requests.post( endpoint, timeout=settings.SIGNING_SERVER_TIMEOUT, data={'addon_id': get_id(file_obj.version.addon)}, files={'file': (u'mozilla.sf', unicode(jar.signatures))}) if response.status_code != 200: msg = u'Posting to add-on signing failed: {0}'.format(response.reason) log.error(msg) raise SigningError(msg) pkcs7 = b64decode(json.loads(response.content)['mozilla.rsa']) cert_serial_num = get_signature_serial_number(pkcs7) jar.make_signed(pkcs7, sigpath=u'mozilla') shutil.move(temp_filename, file_obj.file_path) return cert_serial_num
def extract_lang(project, locale, paths, entities=False): """Extract .lang files from paths and save or update in DB.""" for path in paths: lang = parse_lang(path) relative_path = get_relative_path(path, locale) resource, created = Resource.objects.get_or_create( project=project, path=relative_path) if entities: for key, value in lang: save_entity(resource=resource, string=key, comment=value[1]) update_entity_count(resource, project) else: for key, value in lang: if key != value[2] or '{ok}' in value[3]: try: e = Entity.objects.get(resource=resource, string=key) save_translation( entity=e, locale=locale, string=value[2]) except Entity.DoesNotExist: continue update_stats(resource, locale) log.debug("[" + locale.code + "]: " + path + " saved to DB.")
def post_save(self, obj, created=False): app = obj.addon if created: mkt.log(mkt.LOG.ADD_REVIEW, app, obj) log.debug('[Review:%s] Created by user %s ' % (obj.pk, self.request.user.id)) record_action('new-review', self.request, {'app-id': app.id}) else: mkt.log(mkt.LOG.EDIT_REVIEW, app, obj) log.debug('[Review:%s] Edited by %s' % (obj.pk, self.request.user.id))
def destroy(self, request, *args, **kwargs): obj = self.get_object() mkt.log(mkt.LOG.DELETE_REVIEW, obj.addon, obj, details=dict(title=unicode(obj.title), body=unicode(obj.body), addon_id=obj.addon.id, addon_title=unicode(obj.addon.name))) log.debug('[Review:%s] Deleted by %s' % (obj.pk, self.request.user.id)) return super(RatingViewSet, self).destroy(request, *args, **kwargs)
def start_purchase(request, addon): log.debug('Starting purchase of app: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.get_price(region=request.REGION.id) uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # L10n: {0} is the addon name. contrib_for = (_(u'Firefox Marketplace purchase of {0}').format( addon.name)) currency = request.REGION.default_currency return amount, currency, uuid_, contrib_for
def clean_name(name, instance=None): if not instance: log.debug('clean_name called without an instance: %s' % name) id = reverse_name_lookup(name) # If we get an id and either there's no instance or the instance.id != id. if id and (not instance or id != instance.id): raise forms.ValidationError(_('This name is already in use. Please ' 'choose another.')) return name
def calculate_activity_rating(pks,**kw): ids_str = ','.join(map(str, pks)) log.debug('ES starting calculate_activity_rating for packages: [%s]' % ids_str) for package in Package.objects.filter(pk__in=pks): package.activity_rating = package.calc_activity_rating() package.save() log.debug('ES completed calculate_activity_rating for packages: [%s]' % ids_str)
def add(request, addon): form = forms.ReviewForm(request.POST or None) if request.method == 'POST': if form.is_valid(): details = _review_details(request, addon, form) review = Review.objects.create(**details) amo.log(amo.LOG.ADD_REVIEW, addon, review) log.debug('New review: %s' % review.id) return redirect('reviews.list', addon.slug) return jingo.render(request, 'reviews/add.html', dict(addon=addon, form=form))
def zip_source(pk, hashtag, tqueued=None, **kw): if not hashtag: log.critical("[zip] No hashtag provided") return tstart = time.time() if tqueued: tinqueue = (tstart - tqueued) * 1000 statsd.timing('zip.queued', tinqueue) log.info('[zip:%s] Addon job picked from queue (%dms)' % (hashtag, tinqueue)) log.debug("[zip:%s] Compressing" % pk) PackageRevision.objects.get(pk=pk).zip_source(hashtag=hashtag, tstart=tstart) log.debug("[zip:%s] Compressed" % pk)
def sdk_copy(sdk_source, sdk_dir): log.debug("Copying SDK from (%s) to (%s)" % (sdk_source, sdk_dir)) with statsd.timer('xpi.copy'): if os.path.isdir(sdk_dir): for d in os.listdir(sdk_source): s_d = os.path.join(sdk_source, d) if os.path.isdir(s_d): shutil.copytree(s_d, os.path.join(sdk_dir, d)) else: shutil.copy(s_d, sdk_dir) else: shutil.copytree(sdk_source, sdk_dir)
def create_receipt(sender, instance, **kw): """ When the AddonPurchase gets created, see if we need to create a receipt. """ if (kw.get('raw') or instance.addon.type != amo.ADDON_WEBAPP or instance.receipt): return log.debug('Creating receipt for: addon %s, user %s' % (instance.addon.pk, instance.user.pk)) instance.create_receipt() instance.save()
def expired_resetcode(): """ Delete password reset codes that have expired. """ log.debug('Removing reset codes that have expired...') cursor = connection.cursor() cursor.execute(""" UPDATE users SET resetcode=DEFAULT, resetcode_expires=DEFAULT WHERE resetcode_expires < NOW() """) transaction.commit_unless_managed()
def post(self, request, *args, **kwargs): form = PrepareWebAppForm(request.DATA) if not form.is_valid(): return Response(form.errors, status=status.HTTP_400_BAD_REQUEST) app = form.cleaned_data['app'] region = getattr(request, 'REGION', None) if region: enabled_regions = app.get_price_region_ids() region_can_purchase = region.id in enabled_regions restofworld_can_purchase = RESTOFWORLD.id in enabled_regions if not region_can_purchase and not restofworld_can_purchase: log.info('Region {0} is not in {1}; ' 'restofworld purchases are inactive'.format( region.id, enabled_regions)) return Response( {'reason': 'Payments are restricted for this region'}, status=status.HTTP_403_FORBIDDEN) if app.is_premium() and app.has_purchased(request._request.user): log.info('Already purchased: {0}'.format(app.pk)) return Response({'reason': u'Already purchased app.'}, status=status.HTTP_409_CONFLICT) app_pay_cef.log(request._request, 'Preparing JWT', 'preparing_jwt', 'Preparing JWT for: {0}'.format(app.pk), severity=3) log.debug('Starting purchase of app: {0} by user: {1}'.format( app.pk, request._request.user)) contribution = Contribution.objects.create( addon_id=app.pk, amount=app.get_price(region=request._request.REGION.id), paykey=None, price_tier=app.premium.price, source=request._request.GET.get('src', ''), source_locale=request._request.LANG, type=mkt.CONTRIB_PENDING, user=request._request.user, uuid=str(uuid.uuid4()), ) log.debug('Storing contrib for uuid: {0}'.format(contribution.uuid)) token = get_product_jwt(WebAppProduct(app), contribution) return Response(token, status=status.HTTP_201_CREATED)
def handle(self, *args, **options): start = datetime.datetime.now() # Measure the time it takes to run. # The theme_update_counts_from_* gather data for the day before, at # best. yesterday = datetime.date.today() - datetime.timedelta(days=1) # Average number of users over the last 7 days (0 to 6 days ago). last_week_avgs = ThemeUpdateCount.objects.get_range_days_avg( start=yesterday - datetime.timedelta(days=6), end=yesterday) # Average number of users over the three weeks before last week # (7 to 27 days ago). prev_3_weeks_avgs = ThemeUpdateCount.objects.get_range_days_avg( start=yesterday - datetime.timedelta(days=27), end=yesterday - datetime.timedelta(days=7)) # Perf: memoize the addon to persona relation. addon_to_persona = dict(Persona.objects.values_list('addon_id', 'id')) temp_update_counts = [] for addon_id, popularity in last_week_avgs.iteritems(): if addon_id not in addon_to_persona: continue # Create the temporary ThemeUpdateCountBulk for later bulk create. prev_3_weeks_avg = prev_3_weeks_avgs.get(addon_id, 0) tucb = ThemeUpdateCountBulk(persona_id=addon_to_persona[addon_id], popularity=popularity, movers=0) # Set movers to 0 if values aren't high enough. if popularity > 100 and prev_3_weeks_avg > 1: tucb.movers = (popularity - prev_3_weeks_avg) / prev_3_weeks_avg temp_update_counts.append(tucb) # Create in bulk: this is much faster. ThemeUpdateCountBulk.objects.all().delete() # Clean slate first. ThemeUpdateCountBulk.objects.bulk_create(temp_update_counts, 100) # Update in bulk from the above temp table: again, much faster. # TODO: remove _tmp from the fields when the ADI stuff is used raw_query = """ UPDATE personas p, theme_update_counts_bulk t SET p.popularity_tmp=t.popularity, p.movers_tmp=t.movers WHERE t.persona_id=p.id """ cursor = connection.cursor() cursor.execute(raw_query) log.debug('Total processing time: %s' % (datetime.datetime.now() - start))
def get_product_jwt(product, contribution): """ Prepare a JWT describing the item about to be purchased when working with navigator.mozPay(). See the MDN docs for details on the JWT fields: https://developer.mozilla.org/en-US/Marketplace/Monetization /In-app_payments_section/mozPay_iap """ issued_at = calendar.timegm(time.gmtime()) product_data = product.product_data(contribution) simulation = product.simulation() if not simulation and not product_data.get('public_id'): raise ValueError( 'Cannot create JWT without a cached public_id for ' 'app {a}'.format(a=product.addon())) token_data = { 'iss': settings.APP_PURCHASE_KEY, 'typ': settings.APP_PURCHASE_TYP, 'aud': settings.APP_PURCHASE_AUD, 'iat': issued_at, 'exp': issued_at + 3600, # expires in 1 hour 'request': { 'id': product.external_id(), 'name': unicode(product.name()), 'defaultLocale': product.default_locale(), 'locales': product.localized_properties(), 'icons': product.icons(), 'description': strip_tags(product.description()), 'pricePoint': product.price().name, 'productData': urlencode(product_data), 'chargebackURL': absolutify(reverse('webpay.chargeback')), 'postbackURL': absolutify(reverse('webpay.postback')), } } if simulation: token_data['request']['simulate'] = simulation token = sign_webpay_jwt(token_data) log.debug('Preparing webpay JWT for product {p}, contrib {c}: {t}' .format(p=product.id(), t=token_data, c=contribution)) return { 'webpayJWT': token, 'contribStatusURL': reverse( 'webpay-status', kwargs={'uuid': contribution.uuid} ) }
def _append_task(t): """Append a task to the queue. Expected argument is a tuple of the (task class, args, kwargs). This doesn't append to queue if the argument is already in the queue. """ queue = _get_task_queue() if t not in queue: queue.append(t) else: log.debug('Removed duplicate task: %s' % (t, ))
def email_confirmation_code(self): from amo.utils import send_mail log.debug("Sending account confirmation code for user (%s)", self) url = "%s%s" % (settings.SITE_URL, reverse('users.confirm', args=[self.id, self.confirmationcode])) domain = settings.DOMAIN t = loader.get_template('users/email/confirm.ltxt') c = {'domain': domain, 'url': url, } send_mail(_("Please confirm your email address"), t.render(Context(c)), None, [self.email], use_blacklist=False)
def mkt_gc(**kw): """Site-wide garbage collections.""" days_ago = lambda days: datetime.today() - timedelta(days=days) log.debug('Collecting data to delete') logs = (ActivityLog.objects.filter(created__lt=days_ago(90)).exclude( action__in=amo.LOG_KEEP).values_list('id', flat=True)) for chunk in chunked(logs, 100): chunk.sort() log.debug('Deleting log entries: %s' % str(chunk)) amo.tasks.delete_logs.delay(chunk)
def delete_icon(request, collection, username, slug): log.debug(u"User deleted collection (%s) icon " % slug) tasks.delete_icon( os.path.join(collection.get_img_dir(), '%d.png' % collection.id)) collection.icontype = '' collection.save() if request.is_ajax(): return {'icon': collection.icon_url} else: messages.success(request, _('Icon Deleted')) return redirect(collection.edit_url())
def delete_photo(request): u = request.amo_user if request.method == 'POST': u.picture_type = '' u.save() log.debug(u"User (%s) deleted photo" % u) tasks.delete_photo.delay(u.picture_path) messages.success(request, _('Photo Deleted')) return http.HttpResponseRedirect( reverse('users.edit') + '#user-profile') return render(request, 'users/delete_photo.html', dict(user=u))
def watch_email(old_attr=None, new_attr=None, instance=None, sender=None, **kw): if old_attr is None: old_attr = {} if new_attr is None: new_attr = {} new_email, old_email = new_attr.get('email'), old_attr.get('email') if old_email and new_email != old_email: log.debug('Creating user history for user: %s' % instance.pk) UserHistory.objects.create(email=old_email, user_id=instance.pk)
def save_upsold(self, obj, upsold): current_upsell = obj.upsold if upsold and upsold != obj.upsold.free: if not current_upsell: log.debug('[1@%s] Creating app upsell' % obj.pk) current_upsell = AddonUpsell(premium=obj) current_upsell.free = upsold current_upsell.save() elif current_upsell: # We're deleting the upsell. log.debug('[1@%s] Deleting the app upsell' % obj.pk) current_upsell.delete()
def create_user(self, username, email, fxa_id=None): # We'll send username=None when registering through FxA to generate # an anonymous username. now = timezone.now() user = self.model( username=username, email=email, fxa_id=fxa_id, last_login=now) if username is None: user.anonymize_username() log.debug('Creating user with email {} and username {}'.format( email, username)) user.save(using=self._db) return user
def handle(self, *args, **kw): apps = {} for id, guid in Application.objects.values_list('id', 'guid'): apps[id] = dict(guid=guid, versions=[], name=amo.APPS_ALL[id].short) versions = (AppVersion.objects.values_list( 'application', 'version').order_by('version_int')) for app, version in versions: apps[app]['versions'].append(version) with open(self.JSON_PATH, 'w') as f: json.dump(apps, f) log.debug("Wrote: %s" % f.name)
def create_addon_purchase(sender, instance, **kw): """ When the contribution table is updated with the data from PayPal, update the addon purchase table. Will figure out if we need to add to or delete from the AddonPurchase table. """ if (kw.get('raw') or instance.type not in [ mkt.CONTRIB_PURCHASE, mkt.CONTRIB_REFUND, mkt.CONTRIB_CHARGEBACK ]): # Filter the types we care about. Forget about the rest. return log.info('Processing addon purchase type: {t}, addon {a}, user {u}'.format( t=unicode(mkt.CONTRIB_TYPES[instance.type]), a=instance.addon and instance.addon.pk, u=instance.user and instance.user.pk)) if instance.is_inapp_simulation(): log.info('Simulated in-app product {i} for contribution {c}: ' 'not adding a purchase record'.format( i=instance.inapp_product, c=instance)) return if instance.type == mkt.CONTRIB_PURCHASE: log.debug('Creating addon purchase: addon %s, user %s' % (instance.addon.pk, instance.user.pk)) data = {'addon': instance.addon, 'user': instance.user} purchase, created = AddonPurchase.objects.safer_get_or_create(**data) purchase.update(type=mkt.CONTRIB_PURCHASE) from mkt.webapps.models import Installed # Circular import # Ensure that devs have the correct installed object found # or created. # is_dev = instance.addon.has_author( instance.user, (mkt.AUTHOR_ROLE_OWNER, mkt.AUTHOR_ROLE_DEV)) install_type = (apps.INSTALL_TYPE_DEVELOPER if is_dev else apps.INSTALL_TYPE_USER) Installed.objects.safer_get_or_create(user=instance.user, addon=instance.addon, install_type=install_type) elif instance.type in [mkt.CONTRIB_REFUND, mkt.CONTRIB_CHARGEBACK]: purchases = AddonPurchase.objects.filter(addon=instance.addon, user=instance.user) for p in purchases: log.debug('Changing addon purchase: %s, addon %s, user %s' % (p.pk, instance.addon.pk, instance.user.pk)) p.update(type=instance.type) cache.delete(memoize_key('users:purchase-ids', instance.user.pk))
def index_all(pks, **kw): ids_str = ','.join(map(str, pks)) log.debug('ES starting bulk action for packages: [%s]' % ids_str) for package in Package.objects.filter(pk__in=pks): package.refresh_index(bulk=True) try: get_es().flush_bulk(forced=True) except KeyboardInterrupt: raise except Exception, e: log.error('ES failed bulk action (%s), package ids: [%s]' % (e, ids_str))
def add_can_localize(user): email = user.email log.debug(email) # Grant permission to Mozilla localizers url = "https://mozillians.org/api/v1/users/" payload = { "app_name": "pontoon", "app_key": settings.MOZILLIANS_API_KEY, "email": email, "is_vouched": True, "groups": "localization", } try: response = requests.get(url, params=payload) mozillians = response.json()["objects"] if len(mozillians) > 0: can_localize = Permission.objects.get(codename="can_localize") user.user_permissions.add(can_localize) log.debug("Permission can_localize set.") # Fallback if profile does not allow accessing data user.first_name = mozillians[0].get("full_name", email) user.save() except Exception as e: log.debug(e) log.debug("Is your MOZILLIANS_API_KEY set?") user.save()
def clean_old_signed(seconds=60 * 60): """Clean out apps signed for reviewers.""" log.info('Removing old apps signed for reviewers') root = settings.SIGNED_APPS_REVIEWER_PATH # Local storage uses local time for file modification. S3 uses UTC time. now = datetime.utcnow if storage_is_remote() else datetime.now for nextroot, dirs, files in walk_storage(root, storage=private_storage): for fn in files: full = os.path.join(nextroot, fn) age = now() - private_storage.modified_time(full) if age.total_seconds() > seconds: log.debug('Removing signed app: %s, %dsecs old.' % (full, age.total_seconds())) private_storage.delete(full)
def upload_to_amo(request, pk): """Upload a XPI to AMO """ # check if there this Add-on was uploaded with the same version name revision = get_object_or_404(PackageRevision, pk=pk) version = revision.get_version_name() uploaded = PackageRevision.objects.filter(package=revision.package).filter( amo_version_name=version).exclude(amo_status=None).exclude( amo_status=STATUS_UPLOAD_FAILED).exclude( amo_status=STATUS_UPLOAD_SCHEDULED) if len(uploaded) > 0: log.debug("This Add-on was already uploaded using version \"%s\"" % version) log.debug(revision.amo_status) return HttpResponseBadRequest( "This Add-on was already uploaded using version \"%s\"" % version) try: PackageRevision.objects.get(package=revision.package, amo_version_name=version, amo_status=STATUS_UPLOAD_SCHEDULED) except PackageRevision.DoesNotExist: pass else: log.debug("This Add-on is currently scheduled to upload") return HttpResponseBadRequest( "This Add-on is currently scheduled to upload") log.debug('AMOOAUTH: Scheduling upload to AMO') tasks.upload_to_amo.delay(pk) return HttpResponse('{"delayed": true}')
def _redirect(request, login_url, redirect_field_name): """Redirects the request based on parameters.""" path = request.build_absolute_uri() # If the login url is the same scheme and net location then just # use the path as the "next" url. login_scheme, login_netloc = urlparse.urlparse(login_url or settings.LOGIN_URL)[:2] current_scheme, current_netloc = urlparse.urlparse(path)[:2] if ((not login_scheme or login_scheme == current_scheme) and (not login_netloc or login_netloc == current_netloc)): path = request.get_full_path() log.debug('Clearing user session') logout(request) return redirect_to_login(path, login_url, redirect_field_name)
def change_password(unique_id, oldpass, password): """Changes a user's password.""" dn = Person.dn(unique_id) conn = ldap.initialize(settings.LDAP_SYNC_PROVIDER_URI) try: conn.bind_s(dn, oldpass) conn.passwd_s(dn, None, password) log.debug("Changed %s password" % dn) return True except Exception, e: log.error("Password change failed %s", e) return False
def post(self, request, *args, **kwargs): form = PrepareInAppForm(request.DATA) if not form.is_valid(): app_pay_cef.log( request._request, 'Preparing InApp JWT Failed', 'preparing_inapp_jwt_failed', 'Preparing InApp JWT Failed error: {0}'.format(form.errors), severity=3 ) return Response(form.errors, status=status.HTTP_400_BAD_REQUEST) inapp = form.cleaned_data['inapp'] app_pay_cef.log( request._request, 'Preparing InApp JWT', 'preparing_inapp_jwt', 'Preparing InApp JWT for: {0}'.format(inapp.pk), severity=3 ) log.debug('Starting purchase of in app: {0}'.format(inapp.pk)) contribution = Contribution.objects.create( addon_id=inapp.webapp and inapp.webapp.pk, inapp_product=inapp, # In-App payments are unauthenticated so we have no user # and therefore can't determine a meaningful region. amount=None, paykey=None, price_tier=inapp.price, source=request._request.GET.get('src', ''), source_locale=request._request.LANG, type=mkt.CONTRIB_PENDING, user=None, uuid=str(uuid.uuid4()), ) log.info('Storing contrib for uuid: {0}'.format(contribution.uuid)) if inapp.simulate: log.info('Preparing in-app JWT simulation for {i}' .format(i=inapp)) product = SimulatedInAppProduct(inapp) else: log.info('Preparing in-app JWT for {i}'.format(i=inapp)) product = InAppProduct(inapp) token = get_product_jwt(product, contribution) return Response(token, status=status.HTTP_201_CREATED)