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. qs = self._meta.queryset.filter(addon=app, user=request.user) if app.is_packaged: qs = qs.filter(version_id=bundle.data.get("version", app.current_version.id)) if qs.exists(): raise http_error(http.HttpConflict, "You have already reviewed this app.") # Return 403 if the user is attempting to review their own app: if app.has_author(request.user): raise http_error(http.HttpForbidden, "You may not review your own app.") # 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 http_error(http.HttpForbidden, "You may not review paid apps you haven't purchased.") 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 obj_create(self, bundle, request, **kwargs): form = UploadForm(bundle.data) if not request.amo_user.read_dev_agreement: log.info(u'Attempt to use API without dev agreement: %s' % request.amo_user.pk) raise http_error(http.HttpUnauthorized, 'Terms of service not accepted.') if not form.is_valid(): raise self.form_errors(form) if not (OwnerAuthorization() .is_authorized(request, object=form.obj)): raise http_error(http.HttpForbidden, 'You do not own that app.') plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)] # Create app, user and fetch the icon. bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged) AddonUser(addon=bundle.obj, user=request.amo_user).save() self._icons_and_images(bundle.obj) record_action('app-submitted', request, {'app-id': bundle.obj.pk}) log.info('App created: %s' % bundle.obj.pk) return bundle
def perform_create(self, serializer): serializer.save() app = serializer.instance.addon mkt.log(mkt.LOG.ADD_REVIEW, app, serializer.instance) log.debug('[Review:%s] Created by user %s ' % (serializer.instance.pk, self.request.user.id)) record_action('new-review', self.request, {'app-id': app.id})
def perform_create(self, serializer): serializer.save() app = serializer.instance.addon mkt.log(mkt.LOG.ADD_REVIEW, app, serializer.instance) log.debug('[Review:%s] Created by user %s ' % (serializer.instance.pk, self.request.user.id)) record_action('new-review', self.request, {'app-id': app.id})
def _fxa_authorize(fxa, client_secret, request, auth_response): token = fxa.fetch_token( fxa_oauth_api('token'), authorization_response=auth_response, client_secret=client_secret) res = fxa.post(fxa_oauth_api('verify'), data=json.dumps({'token': token['access_token']}), headers={'Content-Type': 'application/json'}) data = res.json() if 'user' in data: email = data['email'] username = data['user'] try: profile = UserProfile.objects.get(email=email) except UserProfile.DoesNotExist: source = amo.LOGIN_SOURCE_FXA profile = UserProfile.objects.create( username=username, email=email, source=source, display_name=email.partition('@')[0], is_verified=True) log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from FxA)') record_action('new-user', request) auth.login(request, profile) profile.log_login_attempt(True) auth.signals.user_logged_in.send( sender=profile.__class__, request=request, user=profile) return profile
def obj_create(self, bundle, request, **kwargs): form = UploadForm(bundle.data) if not request.amo_user.read_dev_agreement: log.info(u'Attempt to use API without dev agreement: %s' % request.amo_user.pk) response = http.HttpUnauthorized() response.content = json.dumps({'reason': 'Terms of service not accepted.'}) raise ImmediateHttpResponse(response=response) if not form.is_valid(): raise self.form_errors(form) if not (OwnerAuthorization() .is_authorized(request, object=form.obj)): raise ImmediateHttpResponse(response=http.HttpForbidden()) plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)] # Create app, user and fetch the icon. bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged) AddonUser(addon=bundle.obj, user=request.amo_user).save() self._icons_and_images(bundle.obj) record_action('app-submitted', request, {'app-id': bundle.obj.pk}) log.info('App created: %s' % bundle.obj.pk) return bundle
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 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 create(self, request, *args, **kwargs): uuid = request.DATA.get("upload", "") if uuid: is_packaged = True else: uuid = request.DATA.get("manifest", "") is_packaged = False if not uuid: raise serializers.ValidationError("No upload or manifest specified.") try: upload = FileUpload.objects.get(uuid=uuid) except FileUpload.DoesNotExist: raise exceptions.ParseError("No upload found.") if not upload.valid: raise exceptions.ParseError("Upload not valid.") if not request.user.read_dev_agreement: log.info(u"Attempt to use API without dev agreement: %s" % request.user.pk) raise exceptions.PermissionDenied("Terms of Service not accepted.") if not (upload.user and upload.user.pk == request.user.pk): raise exceptions.PermissionDenied("You do not own that app.") # Create app, user and fetch the icon. obj = Webapp.from_upload(upload, is_packaged=is_packaged) AddonUser(addon=obj, user=request.user).save() tasks.fetch_icon.delay(obj, obj.latest_version.all_files[0]) record_action("app-submitted", request, {"app-id": obj.pk}) log.info("App created: %s" % obj.pk) data = AppSerializer(context=self.get_serializer_context()).to_native(obj) return response.Response(data, status=201, headers={"Location": reverse("app-detail", kwargs={"pk": obj.pk})})
def test_record_action(self, record_stat): request = mock.Mock() request.GET = {'src': 'foo'} request.LANG = 'en' request.META = {'HTTP_USER_AGENT': 'py'} record_action('install', request, {}) record_stat.assert_called_with('install', request, **{'locale': 'en', 'src': 'foo', 'user-agent': 'py'})
def record(request, app): amo.log(amo.LOG.INSTALL_ADDON, app) domain = app.domain_from_url(app.origin, allow_none=True) record_action('install', request, { 'app-domain': domain, 'app-id': app.pk, 'anonymous': request.user.is_anonymous(), })
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ extra_params = {} url = settings.NATIVE_FXA_VERIFICATION_URL log.debug("Verifying Native FxA at %s, audience: %s, " "extra_params: %s" % (url, browserid_audience, extra_params)) v = BrowserIDBackend().get_verifier() v.verification_service_url = url result = v.verify(assertion, browserid_audience, url=url, **extra_params) if not result: return None, _("Native FxA authentication failure.") if "unverified-email" in result._response: email = result._response["unverified-email"] verified = False elif result._response.get("issuer") == settings.NATIVE_FXA_ISSUER and "fxa-verifiedEmail" in result._response.get( "idpClaims", {} ): email = result._response["idpClaims"]["fxa-verifiedEmail"] verified = True else: email = result.email verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. Don't let that happen. log.debug("Verified user %s attempted to log in with an " "unverified assertion!" % profile) return None, _("Please use the verified email for this account.") else: profile.is_verified = verified profile.save() return profile, None source = mkt.LOGIN_SOURCE_MMO_BROWSERID display_name = email.partition("@")[0] profile = UserProfile.objects.create(email=email, source=source, display_name=display_name, is_verified=verified) log_cef( "New Account", 5, request, username=display_name, signature="AUTHNOTICE", msg="User created a new account (from Persona)", ) record_action("new-user", request) return profile, None
def _record(request, addon): logged = request.user.is_authenticated() premium = addon.is_premium() # Require login for premium. if not logged and premium: return http.HttpResponseRedirect(reverse('users.login')) ctx = {'addon': addon.pk} # Don't generate receipts if we're allowing logged-out install. if logged: is_dev = request.check_ownership(addon, require_owner=False, ignore_disabled=True, admin=False) is_reviewer = acl.check_reviewer(request) if (not addon.is_public() and not (is_reviewer or is_dev)): raise http.Http404 if (premium and not addon.has_purchased(request.user) and not is_reviewer and not is_dev): raise PermissionDenied # If you are reviewer, you get a user receipt. Use the reviewer tools # to get a reviewer receipt. App developers still get their special # receipt. install = (apps.INSTALL_TYPE_DEVELOPER if is_dev else apps.INSTALL_TYPE_USER) # Log the install. installed, c = Installed.objects.get_or_create(addon=addon, user=request.user, install_type=install) # Get a suitable uuid for this receipt. uuid = get_uuid(addon, request.user) error = '' receipt_cef.log(request, addon, 'sign', 'Receipt requested') try: receipt = create_receipt(addon, request.user, uuid) except SigningError: error = _('There was a problem installing the app.') ctx.update(receipt=receipt, error=error) else: if not addon.is_public(): raise http.Http404 amo.log(amo.LOG.INSTALL_ADDON, addon) record_action( 'install', request, { 'app-domain': addon.domain_from_url(addon.origin, allow_none=True), 'app-id': addon.pk, 'anonymous': request.user.is_anonymous(), }) return ctx
def obj_create(self, bundle, request=None, **kwargs): bundle.data['receipt'] = self.handle(bundle, request=request, **kwargs) amo.log(amo.LOG.INSTALL_ADDON, bundle.obj) record_action('install', request, { 'app-domain': bundle.obj.domain_from_url(bundle.obj.origin), 'app-id': bundle.obj.pk, 'anonymous': request.user.is_anonymous(), }) return bundle
def post_save(self, obj, created=False): app = obj.addon if created: amo.log(amo.LOG.ADD_REVIEW, app, obj) log.debug("[Review:%s] Created by user %s " % (obj.pk, self.request.amo_user.id)) record_action("new-review", self.request, {"app-id": app.id}) else: amo.log(amo.LOG.EDIT_REVIEW, app, obj) log.debug("[Review:%s] Edited by %s" % (obj.pk, self.request.amo_user.id))
def create_action(self, request, serializer): client_id = request.POST.get('client_id', settings.FXA_CLIENT_ID) secret = settings.FXA_SECRETS[client_id] session = OAuth2Session( client_id, scope=u'profile', state=serializer.data['state']) auth_response = serializer.data['auth_response'] fxa_authorization = fxa_authorize(session, secret, auth_response) if 'user' in fxa_authorization: email = fxa_authorization['email'] fxa_uid = fxa_authorization['user'] profile, created = find_or_create_user(email, fxa_uid) if created: log_cef('New Account', 5, request, username=fxa_uid, signature='AUTHNOTICE', msg='User created a new account (from FxA)') record_action('new-user', request) auth.login(request, profile) profile.update(last_login_ip=request.META.get('REMOTE_ADDR', '')) auth.signals.user_logged_in.send(sender=profile.__class__, request=request, user=profile) else: raise AuthenticationFailed('No profile.') request.user = profile request.groups = profile.groups.all() # Remember whether the user has logged in to highlight the register or # sign in nav button. 31536000 == one year. request.set_cookie('has_logged_in', '1', max_age=5 * 31536000) # We want to return completely custom data, not the serializer's. data = { 'error': None, 'token': commonplace_token(request.user.email), 'settings': { 'display_name': request.user.display_name, 'email': request.user.email, 'enable_recommendations': request.user.enable_recommendations, 'source': 'firefox-accounts', } } # Serializers give up if they aren't passed an instance, so we # do that here despite PermissionsSerializer not needing one # really. permissions = PermissionsSerializer(context={'request': request}, instance=True) data.update(permissions.data) # Add ids of installed/purchased/developed apps. data['apps'] = user_relevant_apps(profile) return data
def record(request, app): mkt.log(mkt.LOG.INSTALL_WEBAPP, app) domain = app.domain_from_url(app.origin, allow_none=True) record_action('install', request, { 'app-domain': domain, 'app-id': app.pk, 'region': request.REGION.slug, 'anonymous': request.user.is_anonymous(), })
def record(request, app): amo.log(amo.LOG.INSTALL_ADDON, app) domain = app.domain_from_url(app.origin, allow_none=True) record_action( 'install', request, { 'app-domain': domain, 'app-id': app.pk, 'anonymous': request.user.is_anonymous(), })
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ extra_params = {} url = settings.NATIVE_FXA_VERIFICATION_URL log.debug('Verifying Native FxA at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) v = BrowserIDBackend().get_verifier() v.verification_service_url = url result = v.verify(assertion, browserid_audience, url=url, **extra_params) if not result: return None, _('Native FxA authentication failure.') if 'unverified-email' in result._response: email = result._response['unverified-email'] verified = False elif (result._response.get('issuer') == settings.NATIVE_FXA_ISSUER and 'fxa-verifiedEmail' in result._response.get('idpClaims', {})): email = result._response['idpClaims']['fxa-verifiedEmail'] verified = True else: email = result.email verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. Don't let that happen. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) return None, _('Please use the verified email for this account.') else: profile.is_verified = verified profile.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = amo.LOGIN_SOURCE_MMO_BROWSERID profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def create_action(self, request, serializer): client_id = request.POST.get('client_id', settings.FXA_CLIENT_ID) secret = settings.FXA_SECRETS[client_id] session = OAuth2Session( client_id, scope=u'profile', state=serializer.data['state']) auth_response = serializer.data['auth_response'] fxa_authorization = fxa_authorize(session, secret, auth_response) if 'user' in fxa_authorization: email = fxa_authorization['email'] fxa_uid = fxa_authorization['user'] profile, created = find_or_create_user(email, fxa_uid) if created: log_cef('New Account', 5, request, username=fxa_uid, signature='AUTHNOTICE', msg='User created a new account (from FxA)') record_action('new-user', request) auth.login(request, profile) profile.update(last_login_ip=request.META.get('REMOTE_ADDR', '')) auth.signals.user_logged_in.send(sender=profile.__class__, request=request, user=profile) else: raise AuthenticationFailed('No profile.') request.user = profile request.groups = profile.groups.all() # Remember whether the user has logged in to highlight the register or # sign in nav button. 31536000 == one year. request.set_cookie('has_logged_in', '1', max_age=5 * 31536000) # We want to return completely custom data, not the serializer's. data = { 'error': None, 'token': commonplace_token(request.user.email), 'settings': { 'display_name': request.user.display_name, 'email': request.user.email, 'enable_recommendations': request.user.enable_recommendations, 'source': 'firefox-accounts', } } # Serializers give up if they aren't passed an instance, so we # do that here despite PermissionsSerializer not needing one # really. permissions = PermissionsSerializer(context={'request': request}, instance=True) data.update(permissions.data) # Add ids of installed/purchased/developed apps. data['apps'] = user_relevant_apps(profile) return data
def _record(request, addon): logged = request.user.is_authenticated() premium = addon.is_premium() # Require login for premium. if not logged and premium: return http.HttpResponseRedirect(reverse('users.login')) ctx = {'addon': addon.pk} # Don't generate receipts if we're allowing logged-out install. if logged: is_dev = request.check_ownership(addon, require_owner=False, ignore_disabled=True, admin=False) is_reviewer = acl.check_reviewer(request) if (not addon.is_webapp() or not addon.is_public() and not (is_reviewer or is_dev)): raise http.Http404 if (premium and not addon.has_purchased(request.amo_user) and not is_reviewer and not is_dev): raise PermissionDenied # If you are reviewer, you get a user receipt. Use the reviewer tools # to get a reviewer receipt. App developers still get their special # receipt. install_type = (apps.INSTALL_TYPE_DEVELOPER if is_dev else apps.INSTALL_TYPE_USER) # Log the install. installed, c = Installed.objects.get_or_create(addon=addon, user=request.amo_user, install_type=install_type) # Get a suitable uuid for this receipt. uuid = get_uuid(addon, request.amo_user) error = '' receipt_cef.log(request, addon, 'sign', 'Receipt requested') try: receipt = create_receipt(addon, request.amo_user, uuid) except SigningError: error = _('There was a problem installing the app.') ctx.update(receipt=receipt, error=error) else: if not addon.is_public() or not addon.is_webapp(): raise http.Http404 amo.log(amo.LOG.INSTALL_ADDON, addon) record_action('install', request, { 'app-domain': addon.domain_from_url(addon.origin, allow_none=True), 'app-id': addon.pk, 'anonymous': request.user.is_anonymous(), }) return ctx
def details(request, addon_id, addon): # Name, Slug, Description, Privacy Policy, Homepage URL, Support URL, # Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix="files", queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get("current_locale", "") app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[: -len(form_locale)] else: basename = name + "_" othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = {"form_basic": form_basic, "form_cats": form_cats, "form_icon": form_icon, "form_previews": form_previews} if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) # If this is an incomplete app from the legacy submission flow, it may # not have device types set yet - so assume it works everywhere. if not addon.device_types: for device in amo.DEVICE_TYPES: addon.addondevicetype_set.create(device_type=device) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) if addon.needs_payment(): # Paid apps get STATUS_NULL until payment information and content # ratings entered. addon.update(status=amo.STATUS_NULL, highest_status=amo.STATUS_PENDING) # Mark as pending in special regions (i.e., China). # By default, the column is set to pending when the row is inserted. # But we need to set a nomination date so we know to list the app # in the China Review Queue now (and sort it by that date too). for region in mkt.regions.SPECIAL_REGIONS: addon.geodata.set_nominated_date(region, save=True) log.info(u"[Webapp:%s] Setting nomination date to " u"now for region (%s)." % (addon, region.slug)) record_action("app-submitted", request, {"app-id": addon.pk}) return redirect("submit.app.done", addon.app_slug) ctx = {"step": "details", "addon": addon} ctx.update(forms) return render(request, "submit/details.html", ctx)
def obj_create(self, bundle, request=None, **kwargs): bundle.data['receipt'] = self.handle(bundle, request=request, **kwargs) amo.log(amo.LOG.INSTALL_ADDON, bundle.obj) record_action( 'install', request, { 'app-domain': bundle.obj.domain_from_url(bundle.obj.origin), 'app-id': bundle.obj.pk, 'anonymous': request.user.is_anonymous(), }) return bundle
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 post_save(self, obj, created=False): app = obj.addon if created: amo.log(amo.LOG.ADD_REVIEW, app, obj) log.debug('[Review:%s] Created by user %s ' % (obj.pk, self.request.amo_user.id)) record_action('new-review', self.request, {'app-id': app.id}) else: amo.log(amo.LOG.EDIT_REVIEW, app, obj) log.debug('[Review:%s] Edited by %s' % (obj.pk, self.request.amo_user.id))
def test_record_action(self, record_stat, urlopen): request = mock.Mock() request.GET = {'src': 'foo'} request.LANG = 'en' request.META = {'HTTP_USER_AGENT': 'py'} record_action('install', request, {}) assert record_stat.called data = json.loads(urlopen.call_args[0][0].data) eq_(data['user-agent'], 'py') eq_(data['locale'], 'en') eq_(data['src'], 'foo')
def test_record_action(self, record_stat): request = mock.Mock() request.GET = {'src': 'foo'} request.LANG = 'en' request.META = {'HTTP_USER_AGENT': 'py'} record_action('install', request, {}) record_stat.assert_called_with( 'install', request, **{ 'locale': 'en', 'src': 'foo', 'user-agent': 'py' })
def record(request, app): mkt.log(mkt.LOG.INSTALL_ADDON, app) domain = app.domain_from_url(app.origin, allow_none=True) record_action( "install", request, { "app-domain": domain, "app-id": app.pk, "region": request.REGION.slug, "anonymous": request.user.is_anonymous(), }, )
def _fxa_authorize(fxa, client_secret, request, auth_response, userid): token = fxa.fetch_token(fxa_oauth_api('token'), authorization_response=auth_response, client_secret=client_secret) res = fxa.post(fxa_oauth_api('verify'), data=json.dumps({'token': token['access_token']}), headers={'Content-Type': 'application/json'}) data = res.json() if 'user' in data: email = data['email'] fxa_uid = data['user'] def find_user(**kwargs): try: return UserProfile.objects.get(**kwargs) except UserProfile.DoesNotExist: return None profile = (find_user(pk=userid) or find_user(username=fxa_uid) or find_user(email=email)) if profile: profile.update(username=fxa_uid, email=email) else: profile = UserProfile.objects.create( username=fxa_uid, email=email, source=amo.LOGIN_SOURCE_FXA, display_name=email.partition('@')[0], is_verified=True) log_cef('New Account', 5, request, username=fxa_uid, signature='AUTHNOTICE', msg='User created a new account (from FxA)') record_action('new-user', request) if profile.source != amo.LOGIN_SOURCE_FXA: profile.update(source=amo.LOGIN_SOURCE_FXA) auth.login(request, profile) profile.log_login_attempt(True) auth.signals.user_logged_in.send(sender=profile.__class__, request=request, user=profile) return profile
def _fxa_authorize(fxa, client_secret, request, auth_response, userid): token = fxa.fetch_token( fxa_oauth_api('token'), authorization_response=auth_response, client_secret=client_secret) res = fxa.post(fxa_oauth_api('verify'), data=json.dumps({'token': token['access_token']}), headers={'Content-Type': 'application/json'}) data = res.json() if 'user' in data: email = data['email'] fxa_uid = data['user'] def find_user(**kwargs): try: return UserProfile.objects.get(**kwargs) except UserProfile.DoesNotExist: return None profile = (find_user(pk=userid) or find_user(username=fxa_uid) or find_user(email=email)) if profile: profile.update(username=fxa_uid, email=email) else: profile = UserProfile.objects.create( username=fxa_uid, email=email, source=amo.LOGIN_SOURCE_FXA, display_name=email.partition('@')[0], is_verified=True) log_cef('New Account', 5, request, username=fxa_uid, signature='AUTHNOTICE', msg='User created a new account (from FxA)') record_action('new-user', request) if profile.source != amo.LOGIN_SOURCE_FXA: log.info('Set account to FxA for {0}'.format(email)) statsd.incr('z.mkt.user.fxa') profile.update(source=amo.LOGIN_SOURCE_FXA) auth.login(request, profile) profile.log_login_attempt(True) auth.signals.user_logged_in.send(sender=profile.__class__, request=request, user=profile) return profile
def _get_user_profile(request, buyer_email): user_profile = UserProfile.objects.filter(email=buyer_email) if user_profile.exists(): user_profile = user_profile.get() else: source = mkt.LOGIN_SOURCE_WEBPAY user_profile = UserProfile.objects.create( email=buyer_email, is_verified=True, source=source) log_cef('New Account', 5, request, username=buyer_email, signature='AUTHNOTICE', msg='A new account was created from Webpay (using FxA)') record_action('new-user', request) return user_profile
def _get_user_profile(request, buyer_email): user_profile = UserProfile.objects.filter(email=buyer_email) if user_profile.exists(): user_profile = user_profile.get() else: source = mkt.LOGIN_SOURCE_WEBPAY user_profile = UserProfile.objects.create( email=buyer_email, is_verified=True, source=source) log_cef('New Account', 5, request, username=buyer_email, signature='AUTHNOTICE', msg='A new account was created from Webpay (using FxA)') record_action('new-user', request) return user_profile
def create(self, request, *args, **kwargs): uuid = request.data.get('upload', '') if uuid: is_packaged = True else: uuid = request.data.get('manifest', '') is_packaged = False if not uuid: raise exceptions.ParseError( 'No upload or manifest specified.') try: upload = FileUpload.objects.get(uuid=uuid) except FileUpload.DoesNotExist: raise exceptions.ParseError('No upload found.') if not upload.valid: raise exceptions.ParseError('Upload not valid.') if not request.user.read_dev_agreement: log.info(u'Attempt to use API without dev agreement: %s' % request.user.pk) raise exceptions.PermissionDenied('Terms of Service not accepted.') if not (upload.user and upload.user.pk == request.user.pk): raise exceptions.PermissionDenied('You do not own that app.') # Create app, user and fetch the icon. try: obj = Webapp.from_upload(upload, is_packaged=is_packaged) except (serializers.ValidationError, django_forms.ValidationError) as e: raise exceptions.ParseError(unicode(e)) AddonUser(addon=obj, user=request.user).save() tasks.fetch_icon.delay(obj.pk, obj.latest_version.all_files[0].pk) record_action('app-submitted', request, {'app-id': obj.pk}) log.info('App created: %s' % obj.pk) data = AppSerializer( context=self.get_serializer_context(), instance=obj).data return response.Response( data, status=201, headers={'Location': reverse('app-detail', kwargs={'pk': obj.pk})})
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. qs = self._meta.queryset.filter(addon=app, user=request.user) if app.is_packaged: qs = qs.filter( version_id=bundle.data.get('version', app.current_version.id)) if qs.exists(): raise http_error(http.HttpConflict, 'You have already reviewed this app.') # Return 403 if the user is attempting to review their own app: if app.has_author(request.user): raise http_error(http.HttpForbidden, 'You may not review your own app.') # 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 http_error( http.HttpForbidden, "You may not review paid apps you haven't purchased.") 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 obj_create(self, bundle, request, **kwargs): form = UploadForm(bundle.data) if not form.is_valid(): raise self.form_errors(form) if not (OwnerAuthorization() .is_authorized(request, object=form.obj)): raise ImmediateHttpResponse(response=http.HttpForbidden()) plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)] # Create app, user and fetch the icon. bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged) AddonUser(addon=bundle.obj, user=request.amo_user).save() self._icons_and_images(bundle.obj) record_action('app-submitted', request, {'app-id': bundle.obj.pk}) log.info('App created: %s' % bundle.obj.pk) return bundle
def obj_create(self, bundle, request, **kwargs): form = UploadForm(bundle.data) if not form.is_valid(): raise self.form_errors(form) if not (OwnerAuthorization().is_authorized(request, object=form.obj)): raise ImmediateHttpResponse(response=http.HttpForbidden()) plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)] # Create app, user and fetch the icon. bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged) AddonUser(addon=bundle.obj, user=request.amo_user).save() self._icons_and_images(bundle.obj) record_action('app-submitted', request, {'app-id': bundle.obj.pk}) log.info('App created: %s' % bundle.obj.pk) return bundle
def obj_create(self, bundle, request, **kwargs): form = UploadForm(bundle.data) if not request.amo_user.read_dev_agreement: log.info(u"Attempt to use API without dev agreement: %s" % request.amo_user.pk) raise http_error(http.HttpUnauthorized, "Terms of service not accepted.") if not form.is_valid(): raise self.form_errors(form) if not (OwnerAuthorization().is_authorized(request, object=form.obj)): raise http_error(http.HttpForbidden, "You do not own that app.") plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)] # Create app, user and fetch the icon. bundle.obj = Addon.from_upload(form.obj, plats, is_packaged=form.is_packaged) AddonUser(addon=bundle.obj, user=request.amo_user).save() self._icons_and_images(bundle.obj) record_action("app-submitted", request, {"app-id": bundle.obj.pk}) log.info("App created: %s" % bundle.obj.pk) return bundle
def browserid_authenticate(request, assertion, is_native=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ url = settings.BROWSERID_VERIFICATION_URL # We must always force the Firefox OS identity provider. This is because # we are sometimes allowing unverified assertions and you can't mix that # feature with bridged IdPs. See bug 910938. extra_params = {} if settings.UNVERIFIED_ISSUER: extra_params['experimental_forceIssuer'] = settings.UNVERIFIED_ISSUER if is_native: # When persona is running native on B2G then we can allow unverified # assertions. url = settings.NATIVE_BROWSERID_VERIFICATION_URL extra_params['experimental_allowUnverified'] = 'true' log.debug('Verifying Persona at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) result = verify(assertion, browserid_audience, url=url, extra_params=extra_params) if not result: return None, _('Persona authentication failure.') if 'unverified-email' in result: email = result['unverified-email'] verified = False else: email = result['email'] verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: # Added due to bug 905984. It's possible to have a UserProfile # that has no corresponding User object. if profile.user is None: profile.create_django_user( backend='django_browserid.auth.BrowserIDBackend') if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. However, the same email address # can legitimately be used on the site on desktop and be verified # whilst be used on b2g and be unverified. We are forcing the # issuer, so this shouldn't be an issue. # # Blame kumar. Or cvan. Or deal with it. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) else: profile.is_verified = verified profile.save() backend = 'django_browserid.auth.BrowserIDBackend' if getattr(profile.user, 'backend', None) != backend: profile.user.backend = backend profile.user.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = (amo.LOGIN_SOURCE_MMO_BROWSERID if settings.MARKETPLACE else amo.LOGIN_SOURCE_AMO_BROWSERID) profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) profile.create_django_user( backend='django_browserid.auth.BrowserIDBackend') log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ url = settings.BROWSERID_VERIFICATION_URL # We must always force the Firefox OS identity provider. This is because # we are sometimes allowing unverified assertions and you can't mix that # feature with bridged IdPs. See bug 910938. extra_params = {} if settings.UNVERIFIED_ISSUER: extra_params['experimental_forceIssuer'] = settings.UNVERIFIED_ISSUER if is_mobile: # When persona is running in a mobile OS then we can allow unverified # assertions. url = settings.NATIVE_BROWSERID_VERIFICATION_URL extra_params['experimental_allowUnverified'] = 'true' log.debug('Verifying Persona at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) result = verify(assertion, browserid_audience, url=url, extra_params=extra_params) if not result: return None, _('Persona authentication failure.') if 'unverified-email' in result: email = result['unverified-email'] verified = False else: email = result['email'] verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: # Added due to bug 905984. It's possible to have a UserProfile # that has no corresponding User object. if profile.user is None: profile.create_django_user( backend='django_browserid.auth.BrowserIDBackend') if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. However, the same email address # can legitimately be used on the site on desktop and be verified # whilst be used on b2g and be unverified. We are forcing the # issuer, so this shouldn't be an issue. # # Blame kumar. Or cvan. Or deal with it. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) else: profile.is_verified = verified profile.save() backend = 'django_browserid.auth.BrowserIDBackend' if getattr(profile.user, 'backend', None) != backend: profile.user.backend = backend profile.user.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = (amo.LOGIN_SOURCE_MMO_BROWSERID if settings.MARKETPLACE else amo.LOGIN_SOURCE_AMO_BROWSERID) profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) profile.create_django_user( backend='django_browserid.auth.BrowserIDBackend') log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def details(request, addon_id, addon): # Name, Slug, Description, Privacy Policy, Homepage URL, Support URL, # Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get('current_locale', '') app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[:-len(form_locale)] else: basename = name + '_' othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = { 'form_basic': form_basic, 'form_cats': form_cats, 'form_icon': form_icon, 'form_previews': form_previews, } if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) # If this is an incomplete app from the legacy submission flow, it may # not have device types set yet - so assume it works everywhere. if not addon.device_types: for device in amo.DEVICE_TYPES: addon.addondevicetype_set.create(device_type=device) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) make_public = (amo.PUBLIC_IMMEDIATELY if form_basic.cleaned_data.get('publish') else amo.PUBLIC_WAIT) # Free apps get pushed for review. if addon.premium_type == amo.ADDON_FREE: # The developer doesn't want the app published immediately upon # review. addon.update(status=amo.STATUS_PENDING, make_public=make_public) else: # Paid apps get STATUS_NULL until payment information has been # entered. addon.update(status=amo.STATUS_NULL, highest_status=amo.STATUS_PENDING, make_public=make_public) # Mark the app as excluded in regions that don't support payments. for region in mkt.regions.ALL_REGIONS: if not region.has_payments: AddonExcludedRegion.objects.get_or_create(addon=addon, region=region.id) record_action('app-submitted', request, {'app-id': addon.pk}) return redirect('submit.app.done', addon.app_slug) ctx = { 'step': 'details', 'addon': addon, } ctx.update(forms) return jingo.render(request, 'submit/details.html', ctx)
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ url = settings.BROWSERID_VERIFICATION_URL # We must always force the Firefox OS identity provider. This is because # we are sometimes allowing unverified assertions and you can't mix that # feature with bridged IdPs. See bug 910938. extra_params = {} if settings.UNVERIFIED_ISSUER: extra_params["experimental_forceIssuer"] = settings.UNVERIFIED_ISSUER if is_mobile: # When persona is running in a mobile OS then we can allow unverified # assertions. url = settings.NATIVE_BROWSERID_VERIFICATION_URL extra_params["experimental_allowUnverified"] = "true" log.debug("Verifying Persona at %s, audience: %s, " "extra_params: %s" % (url, browserid_audience, extra_params)) result = verify(assertion, browserid_audience, url=url, extra_params=extra_params) if not result: return None, _("Persona authentication failure.") if "unverified-email" in result: email = result["unverified-email"] verified = False else: email = result["email"] verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: # Added due to bug 905984. It's possible to have a UserProfile # that has no corresponding User object. if profile.user is None: profile.create_django_user(backend="django_browserid.auth.BrowserIDBackend") if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. Don't let that happen. log.debug("Verified user %s attempted to log in with an " "unverified assertion!" % profile) return None, _("Please use the verified email for this account.") else: profile.is_verified = verified profile.save() backend = "django_browserid.auth.BrowserIDBackend" if getattr(profile.user, "backend", None) != backend: profile.user.backend = backend profile.user.save() return profile, None username = autocreate_username(email.partition("@")[0]) source = amo.LOGIN_SOURCE_MMO_BROWSERID if settings.MARKETPLACE else amo.LOGIN_SOURCE_AMO_BROWSERID profile = UserProfile.objects.create( username=username, email=email, source=source, display_name=username, is_verified=verified ) profile.create_django_user(backend="django_browserid.auth.BrowserIDBackend") log_cef( "New Account", 5, request, username=username, signature="AUTHNOTICE", msg="User created a new account (from Persona)", ) if settings.MARKETPLACE: record_action("new-user", request) return profile, None
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ url = settings.BROWSERID_VERIFICATION_URL # We must always force the Firefox OS identity provider. This is because # we are sometimes allowing unverified assertions and you can't mix that # feature with bridged IdPs. See bug 910938. extra_params = {} if settings.UNVERIFIED_ISSUER: extra_params['experimental_forceIssuer'] = settings.UNVERIFIED_ISSUER if is_mobile: # When persona is running in a mobile OS then we can allow unverified # assertions. url = settings.NATIVE_BROWSERID_VERIFICATION_URL extra_params['experimental_allowUnverified'] = 'true' log.debug('Verifying Persona at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) v = BrowserIDBackend().get_verifier() v.verification_service_url = url result = v.verify(assertion, browserid_audience, url=url, **extra_params) if not result: return None, _('Persona authentication failure.') if 'unverified-email' in result._response: email = result._response['unverified-email'] verified = False else: email = result.email verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. Don't let that happen. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) return None, _('Please use the verified email for this account.') else: profile.is_verified = verified profile.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = amo.LOGIN_SOURCE_MMO_BROWSERID profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ extra_params = {} url = settings.NATIVE_FXA_VERIFICATION_URL log.debug('Verifying Native FxA at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) v = BrowserIDBackend().get_verifier() v.verification_service_url = url result = v.verify(assertion, browserid_audience, url=url, **extra_params) if not result: return None, _('Native FxA authentication failure.') if 'unverified-email' in result._response: email = result._response['unverified-email'] verified = False elif (result._response.get('issuer') == settings.NATIVE_FXA_ISSUER and 'fxa-verifiedEmail' in result._response.get('idpClaims', {})): email = result._response['idpClaims']['fxa-verifiedEmail'] verified = True else: email = result.email verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. Don't let that happen. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) return None, _('Please use the verified email for this account.') else: profile.is_verified = verified profile.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = amo.LOGIN_SOURCE_MMO_BROWSERID profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def _record(request, addon): # TODO(andym): we have an API now, replace this with that. logged = request.user.is_authenticated() premium = addon.is_premium() # Require login for premium. if not logged and premium: return http.HttpResponseRedirect(reverse('users.login')) ctx = {'addon': addon.pk} # Don't generate receipts if we're allowing logged-out install. if logged: is_dev = request.check_ownership(addon, require_owner=False, ignore_disabled=True, admin=False) is_reviewer = acl.check_reviewer(request) if (not addon.is_webapp() or not addon.is_public() and not (is_reviewer or is_dev)): raise http.Http404 if (premium and not addon.has_purchased(request.amo_user) and not is_reviewer and not is_dev): raise PermissionDenied # If you are reviewer, you get a user receipt. Use the reviewer tools # to get a reviewer receipt. App developers still get their special # receipt. install_type = (apps.INSTALL_TYPE_DEVELOPER if is_dev else apps.INSTALL_TYPE_USER) # Log the install. installed, c = Installed.objects.safer_get_or_create( addon=addon, user=request.amo_user, install_type=install_type) # Get download source from GET if it exists, if so get the download # source object if it exists. Then grab a client data object to hook up # with the Installed object. download_source = DownloadSource.objects.filter( name=request.REQUEST.get('src', None)) download_source = download_source[0] if download_source else None try: region = request.REGION.id except AttributeError: region = mkt.regions.WORLDWIDE.id client_data, c = ClientData.objects.get_or_create( download_source=download_source, device_type=request.POST.get('device_type', ''), user_agent=request.META.get('HTTP_USER_AGENT', ''), is_chromeless=request.POST.get('chromeless', False), language=request.LANG, region=region) installed.update(client_data=client_data) # Look up to see if its in the receipt cache and log if we have # to recreate it. receipt = memoize_get('create-receipt', installed.pk) error = '' receipt_cef.log(request, addon, 'request', 'Receipt requested') if not receipt: receipt_cef.log(request, addon, 'sign', 'Receipt signing') try: receipt = create_receipt(installed.pk) except SigningError: error = _('There was a problem installing the app.') ctx.update(receipt=receipt, error=error) else: if not addon.is_public() or not addon.is_webapp(): raise http.Http404 amo.log(amo.LOG.INSTALL_ADDON, addon) record_action( 'install', request, { 'app-domain': addon.domain_from_url(addon.origin), 'app-id': addon.pk, 'anonymous': request.user.is_anonymous(), }) return ctx
else: buyer_username = autocreate_username(buyer_email.partition('@')[0]) source = amo.LOGIN_SOURCE_WEBPAY user_profile = UserProfile.objects.create(display_name=buyer_username, email=buyer_email, is_verified=True, source=source, username=buyer_username) log_cef('New Account', 5, request, username=buyer_username, signature='AUTHNOTICE', msg='A new account was created from Webpay (using FxA)') record_action('new-user', request) log.info('webpay postback: fulfilling purchase for contrib %s with ' 'transaction %s' % (contrib, trans_id)) app_pay_cef.log(request, 'Purchase complete', 'purchase_complete', 'Purchase complete for: %s' % (contrib.addon.pk), severity=3) contrib.update(transaction_id=trans_id, type=amo.CONTRIB_PURCHASE, user=user_profile, amount=Decimal(data['response']['price']['amount']), currency=data['response']['price']['currency'])
def details(request, addon_id, addon): # Name, Slug, Description, Privacy Policy, Homepage URL, Support URL, # Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get('current_locale', '') app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[:-len(form_locale)] else: basename = name + '_' othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = { 'form_basic': form_basic, 'form_cats': form_cats, 'form_icon': form_icon, 'form_previews': form_previews, } if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) # If this is an incomplete app from the legacy submission flow, it may # not have device types set yet - so assume it works everywhere. if not addon.device_types: for device in mkt.DEVICE_TYPES: addon.addondevicetype_set.create(device_type=device) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) if addon.needs_payment(): # Paid apps get STATUS_NULL until payment information and content # ratings entered. addon.update(status=mkt.STATUS_NULL, highest_status=mkt.STATUS_PENDING) # Mark as pending in special regions (i.e., China). # By default, the column is set to pending when the row is inserted. # But we need to set a nomination date so we know to list the app # in the China Review Queue now (and sort it by that date too). for region in mkt.regions.SPECIAL_REGIONS: addon.geodata.set_nominated_date(region, save=True) log.info(u'[Webapp:%s] Setting nomination date to ' u'now for region (%s).' % (addon, region.slug)) record_action('app-submitted', request, {'app-id': addon.pk}) return redirect('submit.app.done', addon.app_slug) ctx = { 'step': 'details', 'addon': addon, } ctx.update(forms) return render(request, 'submit/details.html', ctx)
def details(request, addon_id, addon): # Name, Slug, Description, Privacy Policy, Homepage URL, Support URL, # Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get('current_locale', '') app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[:-len(form_locale)] else: basename = name + '_' othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = { 'form_basic': form_basic, 'form_cats': form_cats, 'form_icon': form_icon, 'form_previews': form_previews, } if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) # If this is an incomplete app from the legacy submission flow, it may # not have device types set yet - so assume it works everywhere. if not addon.device_types: for device in amo.DEVICE_TYPES: addon.addondevicetype_set.create(device_type=device) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) make_public = (amo.PUBLIC_IMMEDIATELY if form_basic.cleaned_data.get('publish') else amo.PUBLIC_WAIT) # Free apps get pushed for review. if addon.premium_type == amo.ADDON_FREE: # The developer doesn't want the app published immediately upon # review. addon.update(status=amo.STATUS_PENDING, make_public=make_public) else: # Paid apps get STATUS_NULL until payment information has been # entered. addon.update(status=amo.STATUS_NULL, highest_status=amo.STATUS_PENDING, make_public=make_public) # Mark the app as excluded in regions that don't support payments. for region in mkt.regions.ALL_REGIONS: if not region.has_payments: AddonExcludedRegion.objects.get_or_create( addon=addon, region=region.id) record_action('app-submitted', request, {'app-id': addon.pk}) return redirect('submit.app.done', addon.app_slug) ctx = { 'step': 'details', 'addon': addon, } ctx.update(forms) return jingo.render(request, 'submit/details.html', ctx)
def _record(request, addon): # TODO(andym): we have an API now, replace this with that. logged = request.user.is_authenticated() premium = addon.is_premium() # Require login for premium. if not logged and premium: return http.HttpResponseRedirect(reverse('users.login')) ctx = {'addon': addon.pk} # Don't generate receipts if we're allowing logged-out install. if logged: is_dev = request.check_ownership(addon, require_owner=False, ignore_disabled=True, admin=False) is_reviewer = acl.check_reviewer(request) if (not addon.is_webapp() or not addon.is_public() and not (is_reviewer or is_dev)): raise http.Http404 if (premium and not addon.has_purchased(request.amo_user) and not is_reviewer and not is_dev): raise PermissionDenied # If you are reviewer, you get a user receipt. Use the reviewer tools # to get a reviewer receipt. App developers still get their special # receipt. install_type = (apps.INSTALL_TYPE_DEVELOPER if is_dev else apps.INSTALL_TYPE_USER) # Log the install. installed, c = Installed.objects.get_or_create(addon=addon, user=request.amo_user, install_type=install_type) # Get download source from GET if it exists, if so get the download # source object if it exists. Then grab a client data object to hook up # with the Installed object. download_source = DownloadSource.objects.filter( name=request.REQUEST.get('src', None)) download_source = download_source[0] if download_source else None try: region = request.REGION.id except AttributeError: region = mkt.regions.WORLDWIDE.id client_data, c = ClientData.objects.get_or_create( download_source=download_source, device_type=request.POST.get('device_type', ''), user_agent=request.META.get('HTTP_USER_AGENT', ''), is_chromeless=request.POST.get('chromeless', False), language=request.LANG, region=region) installed.update(client_data=client_data) error = '' receipt_cef.log(request, addon, 'sign', 'Receipt requested') try: receipt = create_receipt(installed) except SigningError: error = _('There was a problem installing the app.') ctx.update(receipt=receipt, error=error) else: if not addon.is_public() or not addon.is_webapp(): raise http.Http404 amo.log(amo.LOG.INSTALL_ADDON, addon) record_action('install', request, { 'app-domain': addon.domain_from_url(addon.origin, allow_none=True), 'app-id': addon.pk, 'anonymous': request.user.is_anonymous(), }) return ctx
def browserid_authenticate(request, assertion, is_native=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ url = settings.BROWSERID_VERIFICATION_URL extra_params = None if is_native: # When persona is running native on B2G then we need to # verify assertions with the right service. # We also need to force the appropriate issuer # for potentially unverified emails. url = settings.NATIVE_BROWSERID_VERIFICATION_URL extra_params = { 'experimental_forceIssuer': settings.UNVERIFIED_ISSUER or False, 'experimental_allowUnverified': 'true' } log.debug('Verifying Persona at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) result = verify(assertion, browserid_audience, url=url, extra_params=extra_params) if not result: return None, _('Persona authentication failure.') if 'unverified-email' in result: email = result['unverified-email'] verified = False else: email = result['email'] verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. However, the same email address # can legitimately be used on the site on desktop and be verified # whilst be used on b2g and be unverified. We are forcing the # issuer, so this shouldn't be an issue. # # Blame kumar. Or cvan. Or deal with it. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) else: profile.is_verified = verified profile.save() backend = 'django_browserid.auth.BrowserIDBackend' if getattr(profile.user, 'backend', None) != backend: profile.user.backend = backend profile.user.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = (amo.LOGIN_SOURCE_MMO_BROWSERID if settings.MARKETPLACE else amo.LOGIN_SOURCE_AMO_BROWSERID) profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) profile.create_django_user( backend='django_browserid.auth.BrowserIDBackend') log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def add(request, addon): if addon.has_author(request.user): # Don't let app owners review their own apps. raise PermissionDenied if (request.user.is_authenticated() and request.method == 'GET' and (not request.MOBILE or request.TABLET)): return detail(request, app_slug=addon.app_slug, add_review=True) # Get user agent of user submitting review. If there is an install with # logged user agent that matches the current user agent, hook up that # install's client data with the rating. If there aren't any install that # match, use the most recent install. This implies that user must have an # install to submit a review, but not sure if that logic is worked in, so # default client_data to None. client_data = None user_agent = request.META.get('HTTP_USER_AGENT', '') install = (Installed.objects.filter(user=request.user, addon=addon) .order_by('-created')) install_w_user_agent = (install.filter(client_data__user_agent=user_agent) .order_by('-created')) has_review = False try: if install_w_user_agent: client_data = install_w_user_agent[0].client_data elif install: client_data = install[0].client_data except ClientData.DoesNotExist: client_data = None data = request.POST or None # Try to get an existing review of the app by this user if we can. filters = dict(addon=addon, user=request.user) if addon.is_packaged: filters['version'] = addon.current_version try: existing_review = Review.objects.valid().filter(**filters)[0] except IndexError: existing_review = None # If the user is posting back, try to process the submission. if data: form = ReviewForm(data) if form.is_valid(): cleaned = form.cleaned_data if existing_review: # If there's a review to overwrite, overwrite it. if (cleaned['body'] != existing_review.body or cleaned['rating'] != existing_review.rating): existing_review.body = cleaned['body'] existing_review.rating = cleaned['rating'] ip = request.META.get('REMOTE_ADDR', '') existing_review.ip_address = ip if 'flag' in cleaned and cleaned['flag']: existing_review.flag = True existing_review.editorreview = True rf = ReviewFlag(review=existing_review, user_id=request.user.id, flag=ReviewFlag.OTHER, note='URLs') rf.save() existing_review.save() amo.log(amo.LOG.EDIT_REVIEW, addon, existing_review) log.debug('[Review:%s] Edited by %s' % (existing_review.id, request.user.id)) messages.success(request, _('Your review was updated successfully!')) # If there is a developer reply to the review, delete it. We do # this per bug 777059. try: reply = existing_review.replies.all()[0] except IndexError: pass else: log.debug('[Review:%s] Deleted reply to %s' % ( reply.id, existing_review.id)) reply.delete() else: # If there isn't a review to overwrite, create a new review. review = Review.objects.create(client_data=client_data, **_review_details( request, addon, form)) if 'flag' in cleaned and cleaned['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('[Review:%s] Created by user %s ' % (review.id, request.user.id)) messages.success(request, _('Your review was successfully added!')) record_action('new-review', request, {'app-id': addon.id}) return redirect(addon.get_ratings_url('list')) # If the form isn't valid, we've set `form` so that it can be used when # the template is rendered below. elif existing_review: # If the user isn't posting back but has an existing review, populate # the form with their existing review and rating. form = ReviewForm({'rating': existing_review.rating or 1, 'body': existing_review.body}) has_review = True else: # If the user isn't posting back and doesn't have an existing review, # just show a blank version of the form. form = ReviewForm() # Get app's support url, either from support flow if contribution exists or # author's support url. support_email = str(addon.support_email) if addon.support_email else None try: contrib_id = (Contribution.objects .filter(user=request.user, addon=addon, type__in=(amo.CONTRIB_PURCHASE, amo.CONTRIB_INAPP, amo.CONTRIB_REFUND)) .order_by('-created')[0].id) support_url = reverse('support', args=[contrib_id]) except IndexError: support_url = addon.support_url return jingo.render(request, 'ratings/add.html', {'product': addon, 'form': form, 'support_url': support_url, 'has_review': has_review, 'support_email': support_email, 'page_parent': addon.get_detail_url() if not existing_review else ''})
def browserid_authenticate(request, assertion, is_mobile=False, browserid_audience=get_audience): """ Verify a BrowserID login attempt. If the BrowserID assertion is good, but no account exists, create one. """ extra_params = {} if waffle.switch_is_active('firefox-accounts'): url = settings.NATIVE_FXA_VERIFICATION_URL else: url = settings.BROWSERID_VERIFICATION_URL # We must always force the Firefox OS identity provider. This is # because we are sometimes allowing unverified assertions and you # can't mix that feature with bridged IdPs. See bug 910938. if settings.UNVERIFIED_ISSUER: extra_params['experimental_forceIssuer'] = settings.UNVERIFIED_ISSUER if is_mobile: # When persona is running in a mobile OS then we can allow # unverified assertions. url = settings.NATIVE_BROWSERID_VERIFICATION_URL extra_params['experimental_allowUnverified'] = 'true' log.debug('Verifying Persona at %s, audience: %s, ' 'extra_params: %s' % (url, browserid_audience, extra_params)) v = BrowserIDBackend().get_verifier() v.verification_service_url = url result = v.verify(assertion, browserid_audience, url=url, **extra_params) if not result: return None, _('Persona authentication failure.') if 'unverified-email' in result._response: email = result._response['unverified-email'] verified = False elif (result._response.get('issuer') == settings.NATIVE_FXA_ISSUER and 'fxa-verifiedEmail' in result._response.get('idpClaims', {})): email = result._response['idpClaims']['fxa-verifiedEmail'] verified = True else: email = result.email verified = True try: profile = UserProfile.objects.filter(email=email)[0] except IndexError: profile = None if profile: if profile.is_verified and not verified: # An attempt to log in to a verified address with an unverified # assertion is a very bad thing. Don't let that happen. log.debug('Verified user %s attempted to log in with an ' 'unverified assertion!' % profile) return None, _('Please use the verified email for this account.') else: profile.is_verified = verified profile.save() return profile, None username = autocreate_username(email.partition('@')[0]) source = amo.LOGIN_SOURCE_MMO_BROWSERID profile = UserProfile.objects.create(username=username, email=email, source=source, display_name=username, is_verified=verified) log_cef('New Account', 5, request, username=username, signature='AUTHNOTICE', msg='User created a new account (from Persona)') record_action('new-user', request) return profile, None
def add(request, addon): if addon.has_author(request.user): # Don't let app owners review their own apps. raise PermissionDenied if (request.user.is_authenticated() and request.method == 'GET' and (not request.MOBILE or request.TABLET)): return detail(request, app_slug=addon.app_slug, add_review=True) # Get user agent of user submitting review. If there is an install with # logged user agent that matches the current user agent, hook up that # install's client data with the rating. If there aren't any install that # match, use the most recent install. This implies that user must have an # install to submit a review, but not sure if that logic is worked in, so # default client_data to None. client_data = None user_agent = request.META.get('HTTP_USER_AGENT', '') install = (Installed.objects.filter(user=request.user, addon=addon).order_by('-created')) install_w_user_agent = (install.filter( client_data__user_agent=user_agent).order_by('-created')) has_review = False try: if install_w_user_agent: client_data = install_w_user_agent[0].client_data elif install: client_data = install[0].client_data except ClientData.DoesNotExist: client_data = None data = request.POST or None # Try to get an existing review of the app by this user if we can. filters = dict(addon=addon, user=request.user) if addon.is_packaged: filters['version'] = addon.current_version try: existing_review = Review.objects.valid().filter(**filters)[0] except IndexError: existing_review = None # If the user is posting back, try to process the submission. if data: form = ReviewForm(data) if form.is_valid(): cleaned = form.cleaned_data if existing_review: # If there's a review to overwrite, overwrite it. if (cleaned['body'] != existing_review.body or cleaned['rating'] != existing_review.rating): existing_review.body = cleaned['body'] existing_review.rating = cleaned['rating'] ip = request.META.get('REMOTE_ADDR', '') existing_review.ip_address = ip if 'flag' in cleaned and cleaned['flag']: existing_review.flag = True existing_review.editorreview = True rf = ReviewFlag(review=existing_review, user_id=request.user.id, flag=ReviewFlag.OTHER, note='URLs') rf.save() existing_review.save() amo.log(amo.LOG.EDIT_REVIEW, addon, existing_review) log.debug('[Review:%s] Edited by %s' % (existing_review.id, request.user.id)) messages.success(request, _('Your review was updated successfully!')) else: # If there isn't a review to overwrite, create a new review. review = Review.objects.create(client_data=client_data, **_review_details( request, addon, form)) if 'flag' in cleaned and cleaned['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('[Review:%s] Created by user %s ' % (review.id, request.user.id)) messages.success(request, _('Your review was successfully added!')) record_action('new-review', request, {'app-id': addon.id}) return redirect(addon.get_ratings_url('list')) # If the form isn't valid, we've set `form` so that it can be used when # the template is rendered below. elif existing_review: # If the user isn't posting back but has an existing review, populate # the form with their existing review and rating. form = ReviewForm({ 'rating': existing_review.rating or 1, 'body': existing_review.body }) has_review = True else: # If the user isn't posting back and doesn't have an existing review, # just show a blank version of the form. form = ReviewForm() support_email = str(addon.support_email) if addon.support_email else None return jingo.render( request, 'ratings/add.html', { 'product': addon, 'form': form, 'support_url': addon.support_url, 'has_review': has_review, 'support_email': support_email, 'page_parent': addon.get_detail_url() if not existing_review else '' })