예제 #1
0
def invite(request):
    profile = request.user.userprofile
    invite_form = None
    vouch_form = None
    if profile.can_vouch:
        invite_form = forms.InviteForm(request.POST or None,
                                       instance=Invite(inviter=profile))
        vouch_form = forms.VouchForm(request.POST or None)

    if invite_form and vouch_form and invite_form.is_valid() and vouch_form.is_valid():
        invite_form.instance.reason = vouch_form.cleaned_data['description']
        invite = invite_form.save()
        invite.send(sender=profile, personal_message=invite_form.cleaned_data['message'])
        msg = _(u"%s has been invited to Mozillians. They'll receive an email "
                u"with instructions on how to join. You can "
                u"invite another Mozillian if you like.") % invite.recipient
        messages.success(request, msg)
        return redirect('phonebook:invite')

    return render(request, 'phonebook/invite.html',
                  {
                      'invite_form': invite_form,
                      'vouch_form': vouch_form,
                      'invites': profile.invites.all(),
                      'vouch_threshold': settings.CAN_VOUCH_THRESHOLD,
                  })
예제 #2
0
def invite(request):
    profile = request.user.userprofile
    invite_form = None
    vouch_form = None
    if profile.can_vouch:
        invite_form = forms.InviteForm(request.POST or None,
                                       instance=Invite(inviter=profile))
        vouch_form = forms.VouchForm(request.POST or None)

    if invite_form and vouch_form and invite_form.is_valid() and vouch_form.is_valid():
        invite_form.instance.reason = vouch_form.cleaned_data['description']
        invite = invite_form.save()
        invite.send(sender=profile, personal_message=invite_form.cleaned_data['message'])
        msg = _(u"%s has been invited to Mozillians. They'll receive an email "
                u"with instructions on how to join. You can "
                u"invite another Mozillian if you like.") % invite.recipient
        messages.success(request, msg)
        return redirect('phonebook:invite')

    return render(request, 'phonebook/invite.html',
                  {
                      'invite_form': invite_form,
                      'vouch_form': vouch_form,
                      'invites': profile.invites.all(),
                      'vouch_threshold': settings.CAN_VOUCH_THRESHOLD,
                  })
예제 #3
0
def change_primary_email(request, email_pk):
    """Change primary email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile
    alternate_emails = ExternalAccount.objects.filter(user=profile,
                                                      type=ExternalAccount.TYPE_EMAIL)

    # Only email owner can change primary email
    if not alternate_emails.filter(pk=email_pk).exists():
        raise Http404()

    alternate_email = alternate_emails.get(pk=email_pk)
    primary_email = user.email

    # Change primary email
    user.email = alternate_email.identifier

    # Turn primary email to alternate
    alternate_email.identifier = primary_email

    with transaction.atomic():
        user.save()
        alternate_email.save()

    return redirect('phonebook:profile_edit')
예제 #4
0
def change_primary_email(request, email_pk):
    """Change primary email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile
    alternate_emails = ExternalAccount.objects.filter(user=profile,
                                                      type=ExternalAccount.TYPE_EMAIL)

    # Only email owner can change primary email
    if not alternate_emails.filter(pk=email_pk).exists():
        raise Http404()

    alternate_email = alternate_emails.get(pk=email_pk)
    primary_email = user.email

    # Change primary email
    user.email = alternate_email.identifier

    # Turn primary email to alternate
    alternate_email.identifier = primary_email

    with transaction.atomic():
        user.save()
        alternate_email.save()
    # Notify Basket about this change
    update_email_in_basket.delay(primary_email, user.email)

    return redirect('phonebook:profile_edit')
예제 #5
0
def delete_apikey(request, api_pk):
    api_key = get_object_or_404(APIv2App,
                                pk=api_pk,
                                owner=request.user.userprofile)
    api_key.delete()
    messages.success(request, _('API key successfully deleted.'))
    return redirect('phonebook:apikeys')
예제 #6
0
def view_profile(request, username):
    """View a profile by username."""
    data = {}
    privacy_mappings = {
        "anonymous": PUBLIC,
        "mozillian": MOZILLIANS,
        "employee": EMPLOYEES,
        "private": PRIVATE,
        "myself": None,
    }
    privacy_level = None

    if request.user.is_authenticated and request.user.username == username:
        # own profile
        view_as = request.GET.get("view_as", "myself")
        privacy_level = privacy_mappings.get(view_as, None)
        profile = UserProfile.objects.privacy_level(privacy_level).get(
            user__username=username
        )
        data["privacy_mode"] = view_as
    else:
        userprofile_query = UserProfile.objects.filter(user__username=username)
        public_profile_exists = userprofile_query.public().exists()
        profile_exists = userprofile_query.exists()
        profile_complete = userprofile_query.exclude(full_name="").exists()

        if not public_profile_exists:
            if not request.user.is_authenticated:
                # you have to be authenticated to continue
                messages.warning(request, LOGIN_MESSAGE)
                return login_required(
                    view_profile, login_url=reverse("phonebook:home")
                )(request, username)

            if not request.user.userprofile.is_vouched:
                # you have to be vouched to continue
                messages.error(request, GET_VOUCHED_MESSAGE)
                return redirect("phonebook:home")

        if not profile_exists or not profile_complete:
            raise Http404

        profile = UserProfile.objects.get(user__username=username)
        profile.set_instance_privacy_level(PUBLIC)
        if request.user.is_authenticated:
            profile.set_instance_privacy_level(request.user.userprofile.privacy_level)

    data["shown_user"] = profile.user
    data["profile"] = profile
    data["primary_identity"] = profile.identity_profiles.filter(
        primary_contact_identity=True
    )
    data["alternate_identities"] = profile.identity_profiles.filter(
        primary_contact_identity=False
    )

    return render(request, "phonebook/profile.html", data)
예제 #7
0
def delete_invite(request, invite_pk):
    profile = request.user.userprofile
    deleted_invite = get_object_or_404(Invite, pk=invite_pk, inviter=profile, redeemed=None)
    deleted_invite.delete()

    msg = (_(u"%s's invitation to Mozillians has been revoked. "
             u"You can invite %s again if you like.") %
            (deleted_invite.recipient, deleted_invite.recipient))
    messages.success(request, msg)
    return redirect('phonebook:invite')
예제 #8
0
def delete_invite(request, invite_pk):
    profile = request.user.userprofile
    deleted_invite = get_object_or_404(Invite, pk=invite_pk, inviter=profile, redeemed=None)
    deleted_invite.delete()

    msg = (_(u"%s's invitation to Mozillians has been revoked. "
             u"You can invite %s again if you like.") %
            (deleted_invite.recipient, deleted_invite.recipient))
    messages.success(request, msg)
    return redirect('phonebook:invite')
예제 #9
0
def view_profile(request, username):
    """View a profile by username."""
    data = {}
    privacy_mappings = {
        'anonymous': PUBLIC,
        'mozillian': MOZILLIANS,
        'employee': EMPLOYEES,
        'private': PRIVATE,
        'myself': None
    }
    privacy_level = None

    if (request.user.is_authenticated() and request.user.username == username):
        # own profile
        view_as = request.GET.get('view_as', 'myself')
        privacy_level = privacy_mappings.get(view_as, None)
        profile = UserProfile.objects.privacy_level(privacy_level).get(
            user__username=username)
        data['privacy_mode'] = view_as
    else:
        userprofile_query = UserProfile.objects.filter(user__username=username)
        public_profile_exists = userprofile_query.public().exists()
        profile_exists = userprofile_query.exists()
        profile_complete = userprofile_query.exclude(full_name='').exists()

        if not public_profile_exists:
            if not request.user.is_authenticated():
                # you have to be authenticated to continue
                messages.warning(request, LOGIN_MESSAGE)
                return (login_required(view_profile,
                                       login_url=reverse('phonebook:home'))(
                                           request, username))

            if not request.user.userprofile.is_vouched:
                # you have to be vouched to continue
                messages.error(request, GET_VOUCHED_MESSAGE)
                return redirect('phonebook:home')

        if not profile_exists or not profile_complete:
            raise Http404

        profile = UserProfile.objects.get(user__username=username)
        profile.set_instance_privacy_level(PUBLIC)
        if request.user.is_authenticated():
            profile.set_instance_privacy_level(
                request.user.userprofile.privacy_level)

    data['shown_user'] = profile.user
    data['profile'] = profile
    data['primary_identity'] = profile.identity_profiles.filter(
        primary_contact_identity=True)
    data['alternate_identities'] = profile.identity_profiles.filter(
        primary_contact_identity=False)

    return render(request, 'phonebook/profile.html', data)
예제 #10
0
def delete_email(request, email_pk):
    """Delete alternate email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile

    # Only email owner can delete emails
    if not ExternalAccount.objects.filter(user=profile, pk=email_pk).exists():
        raise Http404()

    ExternalAccount.objects.get(pk=email_pk).delete()
    return redirect('phonebook:profile_edit')
예제 #11
0
def delete_email(request, email_pk):
    """Delete alternate email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile

    # Only email owner can delete emails
    if not ExternalAccount.objects.filter(user=profile, pk=email_pk).exists():
        raise Http404()

    ExternalAccount.objects.get(pk=email_pk).delete()
    return redirect('phonebook:profile_edit')
예제 #12
0
def unvouch(request, username):
    """Automatically remove all vouches from username.

    This must be behind a waffle flag and activated only for testing
    purposes.

    """
    profile = get_object_or_404(UserProfile, user__username=username)
    profile.vouches_received.all().delete()
    messages.success(request, _('Successfully unvouched user.'))
    return redirect('phonebook:profile_view', profile.user.username)
예제 #13
0
    def process_request(self, request):
        user = request.user
        path = request.path

        if settings.DEBUG:
            self.allow_urls.append(settings.MEDIA_URL)

        if (user.is_authenticated() and not user.userprofile.is_complete and not
                filter(lambda url: re.match(url, path), self.allow_urls)):
            messages.warning(request, _('Please complete registration before proceeding.'))
            return redirect('phonebook:profile_edit')
예제 #14
0
def unvouch(request, username):
    """Automatically remove all vouches from username.

    This must be behind a waffle flag and activated only for testing
    purposes.

    """
    profile = get_object_or_404(UserProfile, user__username=username)
    profile.vouches_received.all().delete()
    messages.success(request, _('Successfully unvouched user.'))
    return redirect('phonebook:profile_view', profile.user.username)
예제 #15
0
def delete_identity(request, identity_pk):
    """Delete alternate email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile

    # Only email owner can delete emails
    idp_query = IdpProfile.objects.filter(profile=profile, pk=identity_pk)
    if not idp_query.exists():
        raise Http404()

    idp_query = idp_query.filter(primary=False, primary_contact_identity=False)
    if idp_query.exists():
        idp_type = idp_query[0].get_type_display()
        idp_query.delete()
        msg = _(u'Identity {0} successfully deleted.'.format(idp_type))
        messages.success(request, msg)
        return redirect('phonebook:profile_edit')

    # We are trying to delete the primary identity, politely ignore the request
    msg = _(u'Sorry the requested Identity cannot be deleted.')
    messages.error(request, msg)
    return redirect('phonebook:profile_edit')
예제 #16
0
def delete_identity(request, identity_pk):
    """Delete alternate email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile

    # Only email owner can delete emails
    idp_query = IdpProfile.objects.filter(profile=profile, pk=identity_pk)
    if not idp_query.exists():
        raise Http404()

    idp_query = idp_query.filter(primary=False, primary_contact_identity=False)
    if idp_query.exists():
        idp_type = idp_query[0].get_type_display()
        idp_query.delete()
        send_userprofile_to_cis.delay(profile.pk)
        msg = _(u'Identity {0} successfully deleted.'.format(idp_type))
        messages.success(request, msg)
        return redirect('phonebook:profile_edit')

    # We are trying to delete the primary identity, politely ignore the request
    msg = _(u'Sorry the requested Identity cannot be deleted.')
    messages.error(request, msg)
    return redirect('phonebook:profile_edit')
예제 #17
0
def register(request):
    """Registers Users.

    Pulls out an invite code if it exists and auto validates the user
    if so. Single-purpose view.
    """
    # TODO already vouched users can be re-vouched?
    if 'code' in request.GET:
        request.session['invite-code'] = request.GET['code']
        if request.user.is_authenticated():
            if not request.user.userprofile.is_vouched:
                redeem_invite(request.user.userprofile, request.session['invite-code'])
        else:
            messages.info(request, _("You've been invited to join Mozillians.org! "
                                     "Sign in and then you can create a profile."))

    return redirect('phonebook:home')
예제 #18
0
def register(request):
    """Registers Users.

    Pulls out an invite code if it exists and auto validates the user
    if so. Single-purpose view.
    """
    # TODO already vouched users can be re-vouched?
    if 'code' in request.GET:
        request.session['invite-code'] = request.GET['code']
        if request.user.is_authenticated():
            if not request.user.userprofile.is_vouched:
                redeem_invite(request.user.userprofile, request.session['invite-code'])
        else:
            messages.info(request, _("You've been invited to join Mozillians.org! "
                                     "Sign in and then you can create a profile."))

    return redirect('phonebook:home')
예제 #19
0
def change_primary_contact_identity(request, identity_pk):
    """Change primary email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile
    alternate_identities = IdpProfile.objects.filter(profile=profile)

    # Only email owner can change primary email
    if not alternate_identities.filter(pk=identity_pk).exists():
        raise Http404()

    if alternate_identities.filter(primary_contact_identity=True).exists():
        alternate_identities.filter(pk=identity_pk).update(primary_contact_identity=True)
        alternate_identities.exclude(pk=identity_pk).update(primary_contact_identity=False)

        msg = _(u'Primary Contact Identity successfully updated.')
        messages.success(request, msg)

    return redirect('phonebook:profile_edit')
예제 #20
0
def change_primary_contact_identity(request, identity_pk):
    """Change primary email address."""
    user = User.objects.get(pk=request.user.id)
    profile = user.userprofile
    alternate_identities = IdpProfile.objects.filter(profile=profile)

    # Only email owner can change primary email
    if not alternate_identities.filter(pk=identity_pk).exists():
        raise Http404()

    if alternate_identities.filter(primary_contact_identity=True).exists():
        alternate_identities.filter(pk=identity_pk).update(primary_contact_identity=True)
        alternate_identities.exclude(pk=identity_pk).update(primary_contact_identity=False)

        msg = _(u'Primary Contact Identity successfully updated.')
        messages.success(request, msg)

    return redirect('phonebook:profile_edit')
예제 #21
0
def apikeys(request):
    profile = request.user.userprofile
    apikey_request_form = forms.APIKeyRequestForm(
        request.POST or None,
        instance=APIv2App(enabled=True, owner=profile)
    )

    if apikey_request_form.is_valid():
        apikey_request_form.save()
        msg = _(u'API Key generated successfully.')
        messages.success(request, msg)
        return redirect('phonebook:apikeys')

    data = {
        'appsv2': profile.apps.filter(enabled=True),
        'apikey_request_form': apikey_request_form,
    }
    return render(request, 'phonebook/apikeys.html', data)
예제 #22
0
def apikeys(request):
    profile = request.user.userprofile
    apikey_request_form = forms.APIKeyRequestForm(
        request.POST or None,
        instance=APIv2App(enabled=True, owner=profile)
    )

    if apikey_request_form.is_valid():
        apikey_request_form.save()
        msg = _(u'API Key generated successfully.')
        messages.success(request, msg)
        return redirect('phonebook:apikeys')

    data = {
        'appsv2': profile.apps.filter(enabled=True),
        'apikey_request_form': apikey_request_form,
    }
    return render(request, 'phonebook/apikeys.html', data)
예제 #23
0
def search(request):
    limit = None
    people = []
    show_pagination = False
    form = forms.SearchForm(request.GET)
    groups = None
    functional_areas = None

    if form.is_valid():
        query = form.cleaned_data.get('q', u'')
        limit = form.cleaned_data['limit']
        include_non_vouched = form.cleaned_data['include_non_vouched']
        page = request.GET.get('page', 1)
        functional_areas = Group.get_functional_areas()
        public = not (request.user.is_authenticated()
                      and request.user.userprofile.is_vouched)

        profiles = UserProfileMappingType.search(
            query, public=public, include_non_vouched=include_non_vouched)
        if not public:
            groups = Group.search(query)

        paginator = Paginator(profiles, limit)

        try:
            people = paginator.page(page)
        except PageNotAnInteger:
            people = paginator.page(1)
        except EmptyPage:
            people = paginator.page(paginator.num_pages)

        if profiles.count() == 1 and not groups:
            return redirect('phonebook:profile_view', people[0].user.username)

        show_pagination = paginator.count > settings.ITEMS_PER_PAGE

    d = dict(people=people,
             search_form=form,
             limit=limit,
             show_pagination=show_pagination,
             groups=groups,
             functional_areas=functional_areas)

    return render(request, 'phonebook/search.html', d)
예제 #24
0
def search(request):
    limit = None
    people = []
    show_pagination = False
    form = forms.SearchForm(request.GET)
    groups = None
    functional_areas = None

    if form.is_valid():
        query = form.cleaned_data.get('q', u'')
        limit = form.cleaned_data['limit']
        include_non_vouched = form.cleaned_data['include_non_vouched']
        page = request.GET.get('page', 1)
        functional_areas = Group.get_functional_areas()
        public = not (request.user.is_authenticated() and
                      request.user.userprofile.is_vouched)

        profiles = UserProfileMappingType.search(
            query, public=public, include_non_vouched=include_non_vouched)
        if not public:
            groups = Group.search(query)

        paginator = Paginator(profiles, limit)

        try:
            people = paginator.page(page)
        except PageNotAnInteger:
            people = paginator.page(1)
        except EmptyPage:
            people = paginator.page(paginator.num_pages)

        if profiles.count() == 1 and not groups:
            return redirect('phonebook:profile_view', people[0].user.username)

        show_pagination = paginator.count > settings.ITEMS_PER_PAGE

    d = dict(people=people,
             search_form=form,
             limit=limit,
             show_pagination=show_pagination,
             groups=groups,
             functional_areas=functional_areas)

    return render(request, 'phonebook/search.html', d)
예제 #25
0
def vouch(request, username):
    """Automatically vouch username.

    This must be behind a waffle flag and activated only for testing
    purposes.

    """
    profile = get_object_or_404(UserProfile, user__username=username)
    now = timezone.now()
    description = 'Automatically vouched for testing purposes on {0}'.format(now)
    vouch = profile.vouch(None, description=description, autovouch=True)
    if vouch:
        messages.success(request, _('Successfully vouched user.'))
    else:
        msg = _('User not vouched. Maybe there are {0} vouches already?')
        msg = msg.format(settings.VOUCH_COUNT_LIMIT)
        messages.error(request, msg)

    return redirect('phonebook:profile_view', profile.user.username)
예제 #26
0
def vouch(request, username):
    """Automatically vouch username.

    This must be behind a waffle flag and activated only for testing
    purposes.

    """
    profile = get_object_or_404(UserProfile, user__username=username)
    now = timezone.now()
    description = 'Automatically vouched for testing purposes on {0}'.format(now)
    vouch = profile.vouch(None, description=description, autovouch=True)
    if vouch:
        messages.success(request, _('Successfully vouched user.'))
    else:
        msg = _('User not vouched. Maybe there are {0} vouches already?')
        msg = msg.format(settings.VOUCH_COUNT_LIMIT)
        messages.error(request, msg)

    return redirect('phonebook:profile_view', profile.user.username)
예제 #27
0
    def process_view(self, request, view_func, view_args, view_kwargs):
        for view_url in self.exceptions:
            if re.match(view_url, request.path):
                return None

        allow_public = getattr(view_func, '_allow_public', None)
        if allow_public:
            return None

        if not request.user.is_authenticated():
            messages.warning(request, LOGIN_MESSAGE)
            return (login_required(view_func, login_url=reverse('phonebook:home'))
                    (request, *view_args, **view_kwargs))

        if request.user.userprofile.is_vouched:
            return None

        allow_unvouched = getattr(view_func, '_allow_unvouched', None)
        if allow_unvouched:
            return None

        messages.error(request, GET_VOUCHED_MESSAGE)
        return redirect('phonebook:home')
예제 #28
0
    def __call__(self, request):
        user = request.user
        path = request.path

        allow_urls = [
            r'^/[\w-]+{0}'.format(reverse('phonebook:logout')),
            r'^/[\w-]+{0}'.format(reverse('phonebook:login')),
            r'^/[\w-]+{0}'.format(reverse('phonebook:profile_edit')),
            r'^/[\w-]+{0}'.format(reverse('groups:skills-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:country-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:region-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:city-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:timezone-autocomplete')),
        ]

        if settings.DEBUG:
            allow_urls.append(settings.MEDIA_URL)

        if (user.is_authenticated() and not user.userprofile.is_complete and not
                filter(lambda url: re.match(url, path), allow_urls)):
            messages.warning(request, _('Please complete registration before proceeding.'))
            return redirect('phonebook:profile_edit')
        return self.get_response(request)
예제 #29
0
    def __call__(self, request):
        user = request.user
        path = request.path

        allow_urls = [
            r'^/[\w-]+{0}'.format(reverse('phonebook:logout')),
            r'^/[\w-]+{0}'.format(reverse('phonebook:login')),
            r'^/[\w-]+{0}'.format(reverse('phonebook:profile_edit')),
            r'^/[\w-]+{0}'.format(reverse('groups:skills-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:country-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:region-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:city-autocomplete')),
            r'^/[\w-]+{0}'.format(reverse('users:timezone-autocomplete')),
        ]

        if settings.DEBUG:
            allow_urls.append(settings.MEDIA_URL)

        if (user.is_authenticated() and not user.userprofile.is_complete and not
                filter(lambda url: re.match(url, path), allow_urls)):
            messages.warning(request, _('Please complete registration before proceeding.'))
            return redirect('phonebook:profile_edit')
        return self.get_response(request)
예제 #30
0
    def process_view(self, request, view_func, view_args, view_kwargs):
        for view_url in self.exceptions:
            if re.match(view_url, request.path):
                return None

        allow_public = getattr(view_func, '_allow_public', None)
        if allow_public:
            return None

        if not request.user.is_authenticated():
            messages.warning(request, LOGIN_MESSAGE)
            return (login_required(view_func, login_url=reverse('phonebook:home'))
                    (request, *view_args, **view_kwargs))

        if request.user.userprofile.is_vouched:
            return None

        allow_unvouched = getattr(view_func, '_allow_unvouched', None)
        if allow_unvouched:
            return None

        messages.error(request, GET_VOUCHED_MESSAGE)
        return redirect('phonebook:home')
예제 #31
0
def view_profile(request, username):
    """View a profile by username."""
    data = {}
    privacy_mappings = {'anonymous': PUBLIC, 'mozillian': MOZILLIANS, 'employee': EMPLOYEES,
                        'privileged': PRIVILEGED, 'myself': None}
    privacy_level = None
    abuse_form = None

    if (request.user.is_authenticated() and request.user.username == username):
        # own profile
        view_as = request.GET.get('view_as', 'myself')
        privacy_level = privacy_mappings.get(view_as, None)
        profile = UserProfile.objects.privacy_level(privacy_level).get(user__username=username)
        data['privacy_mode'] = view_as
    else:
        userprofile_query = UserProfile.objects.filter(user__username=username)
        public_profile_exists = userprofile_query.public().exists()
        profile_exists = userprofile_query.exists()
        profile_complete = userprofile_query.exclude(full_name='').exists()

        if not public_profile_exists:
            if not request.user.is_authenticated():
                # you have to be authenticated to continue
                messages.warning(request, LOGIN_MESSAGE)
                return (login_required(view_profile, login_url=reverse('phonebook:home'))
                        (request, username))

            if not request.user.userprofile.is_vouched:
                # you have to be vouched to continue
                messages.error(request, GET_VOUCHED_MESSAGE)
                return redirect('phonebook:home')

        if not profile_exists or not profile_complete:
            raise Http404

        profile = UserProfile.objects.get(user__username=username)
        profile.set_instance_privacy_level(PUBLIC)
        if request.user.is_authenticated():
            profile.set_instance_privacy_level(
                request.user.userprofile.privacy_level)

        if (request.user.is_authenticated() and request.user.userprofile.is_vouched and
                not profile.can_vouch):
            abuse_report = get_object_or_none(AbuseReport, reporter=request.user.userprofile,
                                              profile=profile)

            if not abuse_report:
                abuse_report = AbuseReport(reporter=request.user.userprofile, profile=profile)

            abuse_form = forms.AbuseReportForm(request.POST or None, instance=abuse_report)
            if abuse_form.is_valid():
                abuse_form.save()
                msg = _(u'Thanks for helping us improve mozillians.org!')
                messages.info(request, msg)
                return redirect('phonebook:profile_view', profile.user.username)

        if (request.user.is_authenticated() and profile.is_vouchable(request.user.userprofile)):

            vouch_form = forms.VouchForm(request.POST or None)
            data['vouch_form'] = vouch_form
            if vouch_form.is_valid():
                # We need to re-fetch profile from database.
                profile = UserProfile.objects.get(user__username=username)
                profile.vouch(request.user.userprofile, vouch_form.cleaned_data['description'])
                # Notify the current user that they vouched successfully.
                msg = _(u'Thanks for vouching for a fellow Mozillian! This user is now vouched!')
                messages.info(request, msg)
                return redirect('phonebook:profile_view', profile.user.username)

    data['shown_user'] = profile.user
    data['profile'] = profile
    data['groups'] = profile.get_annotated_groups()
    data['abuse_form'] = abuse_form

    # Only show pending groups if user is looking at their own profile,
    # or current user is a superuser
    if not (request.user.is_authenticated() and
            (request.user.username == username or request.user.is_superuser)):
        data['groups'] = [grp for grp in data['groups'] if not (grp.pending or grp.pending_terms)]

    return render(request, 'phonebook/profile.html', data)
예제 #32
0
    def get(self, request):
        """Callback handler for OIDC authorization code flow.

        This is based on the mozilla-django-oidc library.
        This callback is used to verify the identity added by the user.
        Users are already logged in and we do not care about authentication.
        The JWT token is used to prove the identity of the user.
        """

        profile = request.user.userprofile
        # This is a difference nonce than the one used to login!
        nonce = request.session.get('oidc_verify_nonce')
        if nonce:
            # Make sure that nonce is not used twice
            del request.session['oidc_verify_nonce']

        # Check for all possible errors and display a message to the user.
        errors = [
            'code' not in request.GET,
            'state' not in request.GET,
            'oidc_verify_state' not in request.session,
            request.GET['state'] != request.session['oidc_verify_state']
        ]
        if any(errors):
            msg = 'Something went wrong, account verification failed.'
            messages.error(request, msg)
            return redirect('phonebook:profile_edit')

        token_payload = {
            'client_id': self.OIDC_RP_VERIFICATION_CLIENT_ID,
            'client_secret': self.OIDC_RP_VERIFICATION_CLIENT_SECRET,
            'grant_type': 'authorization_code',
            'code': request.GET['code'],
            'redirect_uri': absolutify(
                self.request,
                nonprefixed_url('phonebook:verify_identity_callback')
            ),
        }
        response = requests.post(self.OIDC_OP_TOKEN_ENDPOINT,
                                 data=token_payload,
                                 verify=import_from_settings('OIDC_VERIFY_SSL', True))
        response.raise_for_status()
        token_response = response.json()
        id_token = token_response.get('id_token')

        # Verify JWT
        jws = JWS.from_compact(force_bytes(id_token))
        jwk = JWK.load(smart_bytes(self.OIDC_RP_VERIFICATION_CLIENT_SECRET))
        verified_token = None
        if jws.verify(jwk):
            verified_token = jws.payload

        # Create the new Identity Profile.
        if verified_token:
            user_info = json.loads(verified_token)
            email = user_info['email']

            if not user_info.get('email_verified'):
                msg = 'Account verification failed: Email is not verified.'
                messages.error(request, msg)
                return redirect('phonebook:profile_edit')

            user_q = {
                'auth0_user_id': user_info['sub'],
                'email': email
            }

            # If we are linking GitHub we need to save
            # the username too.
            if 'github|' in user_info['sub']:
                user_q['username'] = user_info['nickname']

            # Check that the identity doesn't exist in another Identity profile
            # or in another mozillians profile
            error_msg = ''
            if IdpProfile.objects.filter(**user_q).exists():
                error_msg = 'Account verification failed: Identity already exists.'
            elif User.objects.filter(email__iexact=email).exclude(pk=profile.user.pk).exists():
                error_msg = 'The email in this identity is used by another user.'
            if error_msg:
                messages.error(request, error_msg)
                next_url = self.request.session.get('oidc_login_next', None)
                return HttpResponseRedirect(next_url or reverse('phonebook:profile_edit'))

            # Save the new identity to the IdpProfile
            user_q['profile'] = profile
            idp, created = IdpProfile.objects.get_or_create(**user_q)

            current_idp = get_object_or_none(IdpProfile, profile=profile, primary=True)
            # The new identity is stronger than the one currently used. Let's swap
            append_msg = ''
            # We need to check for equality too in the case a user updates the primary email in
            # the same identity (matching auth0_user_id). If there is an addition of the same type
            # we are not swapping login identities
            if ((current_idp and current_idp.type < idp.type) or
                (current_idp and current_idp.auth0_user_id == idp.auth0_user_id) or
                    (not current_idp and created and idp.type >= IdpProfile.PROVIDER_GITHUB)):
                IdpProfile.objects.filter(profile=profile).exclude(pk=idp.pk).update(primary=False)
                idp.primary = True
                idp.save()
                # Also update the primary email of the user
                update_email_in_basket(profile.user.email, idp.email)
                User.objects.filter(pk=profile.user.id).update(email=idp.email)
                append_msg = ' You need to use this identity the next time you will login.'

            send_userprofile_to_cis.delay(profile.pk)
            if created:
                msg = 'Account successfully verified.'
                if append_msg:
                    msg += append_msg
                messages.success(request, msg)
            else:
                msg = 'Account verification failed: Identity already exists.'
                messages.error(request, msg)

        next_url = self.request.session.get('oidc_login_next', None)
        return HttpResponseRedirect(next_url or reverse('phonebook:profile_edit'))
예제 #33
0
def delete_idp_profiles(request):
    """QA helper: Delete IDP profiles for request.user"""
    request.user.userprofile.idp_profiles.all().delete()
    messages.warning(request, 'Identities deleted.')
    return redirect('phonebook:profile_edit')
예제 #34
0
def logout(request):
    """View that logs out the user and redirects to home page."""
    auth_logout(request)
    return redirect('phonebook:home')
예제 #35
0
    def get(self, request):
        """Callback handler for OIDC authorization code flow.

        This is based on the mozilla-django-oidc library.
        This callback is used to verify the identity added by the user.
        Users are already logged in and we do not care about authentication.
        The JWT token is used to prove the identity of the user.
        """

        profile = request.user.userprofile
        # This is a difference nonce than the one used to login!
        nonce = request.session.get('oidc_verify_nonce')
        if nonce:
            # Make sure that nonce is not used twice
            del request.session['oidc_verify_nonce']

        # Check for all possible errors and display a message to the user.
        errors = [
            'code' not in request.GET, 'state' not in request.GET,
            'oidc_verify_state' not in request.session,
            request.GET['state'] != request.session['oidc_verify_state']
        ]
        if any(errors):
            msg = 'Something went wrong, account verification failed.'
            messages.error(request, msg)
            return redirect('phonebook:profile_edit')

        token_payload = {
            'client_id':
            self.OIDC_RP_VERIFICATION_CLIENT_ID,
            'client_secret':
            self.OIDC_RP_VERIFICATION_CLIENT_SECRET,
            'grant_type':
            'authorization_code',
            'code':
            request.GET['code'],
            'redirect_uri':
            absolutify(self.request,
                       nonprefixed_url('phonebook:verify_identity_callback')),
        }
        response = requests.post(self.OIDC_OP_TOKEN_ENDPOINT,
                                 data=token_payload,
                                 verify=import_from_settings(
                                     'OIDC_VERIFY_SSL', True))
        response.raise_for_status()
        token_response = response.json()
        id_token = token_response.get('id_token')

        # Verify JWT
        jws = JWS.from_compact(force_bytes(id_token))
        jwk = JWK.load(smart_bytes(self.OIDC_RP_VERIFICATION_CLIENT_SECRET))
        verified_token = None
        if jws.verify(jwk):
            verified_token = jws.payload

        # Create the new Identity Profile.
        if verified_token:
            user_info = json.loads(verified_token)
            email = user_info['email']

            if not user_info.get('email_verified'):
                msg = 'Account verification failed: Email is not verified.'
                messages.error(request, msg)
                return redirect('phonebook:profile_edit')

            user_q = {'auth0_user_id': user_info['sub'], 'email': email}

            # If we are linking GitHub we need to save
            # the username too.
            if 'github|' in user_info['sub']:
                user_q['username'] = user_info['nickname']

            # Check that the identity doesn't exist in another Identity profile
            # or in another mozillians profile
            error_msg = ''
            if IdpProfile.objects.filter(**user_q).exists():
                error_msg = 'Account verification failed: Identity already exists.'
            elif User.objects.filter(email__iexact=email).exclude(
                    pk=profile.user.pk).exists():
                error_msg = 'The email in this identity is used by another user.'
            if error_msg:
                messages.error(request, error_msg)
                next_url = self.request.session.get('oidc_login_next', None)
                return HttpResponseRedirect(
                    next_url or reverse('phonebook:profile_edit'))

            # Save the new identity to the IdpProfile
            user_q['profile'] = profile
            idp, created = IdpProfile.objects.get_or_create(**user_q)

            current_idp = get_object_or_none(IdpProfile,
                                             profile=profile,
                                             primary=True)
            # The new identity is stronger than the one currently used. Let's swap
            append_msg = ''
            # We need to check for equality too in the case a user updates the primary email in
            # the same identity (matching auth0_user_id). If there is an addition of the same type
            # we are not swapping login identities
            if ((current_idp and current_idp.type < idp.type)
                    or (current_idp
                        and current_idp.auth0_user_id == idp.auth0_user_id)
                    or (not current_idp and created
                        and idp.type >= IdpProfile.PROVIDER_GITHUB)):
                IdpProfile.objects.filter(profile=profile).exclude(
                    pk=idp.pk).update(primary=False)
                idp.primary = True
                idp.save()
                # Also update the primary email of the user
                update_email_in_basket(profile.user.email, idp.email)
                User.objects.filter(pk=profile.user.id).update(email=idp.email)
                append_msg = ' You need to use this identity the next time you will login.'

            send_userprofile_to_cis.delay(profile.pk)
            if created:
                msg = 'Account successfully verified.'
                if append_msg:
                    msg += append_msg
                messages.success(request, msg)
            else:
                msg = 'Account verification failed: Identity already exists.'
                messages.error(request, msg)

        next_url = self.request.session.get('oidc_login_next', None)
        return HttpResponseRedirect(next_url
                                    or reverse('phonebook:profile_edit'))
예제 #36
0
def login(request):
    if request.user.userprofile.is_complete:
        return redirect('phonebook:home')
    return redirect('phonebook:profile_edit')
예제 #37
0
def login(request):
    if request.user.userprofile.is_complete:
        return redirect('phonebook:home')
    return redirect('phonebook:profile_edit')
예제 #38
0
def delete_apikey(request, api_pk):
    api_key = get_object_or_404(APIv2App, pk=api_pk, owner=request.user.userprofile)
    api_key.delete()
    messages.success(request, _('API key successfully deleted.'))
    return redirect('phonebook:apikeys')
예제 #39
0
def logout(request):
    """View that logs out the user and redirects to home page."""
    auth_logout(request)
    return redirect('phonebook:home')
예제 #40
0
def delete_idp_profiles(request):
    """QA helper: Delete IDP profiles for request.user"""
    request.user.userprofile.idp_profiles.all().delete()
    messages.warning(request, 'Identities deleted.')
    return redirect('phonebook:profile_edit')
예제 #41
0
def view_profile(request, username):
    """View a profile by username."""
    data = {}
    privacy_mappings = {'anonymous': PUBLIC, 'mozillian': MOZILLIANS, 'employee': EMPLOYEES,
                        'privileged': PRIVILEGED, 'myself': None}
    privacy_level = None
    abuse_form = None

    if (request.user.is_authenticated() and request.user.username == username):
        # own profile
        view_as = request.GET.get('view_as', 'myself')
        privacy_level = privacy_mappings.get(view_as, None)
        profile = UserProfile.objects.privacy_level(privacy_level).get(user__username=username)
        data['privacy_mode'] = view_as
    else:
        userprofile_query = UserProfile.objects.filter(user__username=username)
        public_profile_exists = userprofile_query.public().exists()
        profile_exists = userprofile_query.exists()
        profile_complete = userprofile_query.exclude(full_name='').exists()

        if not public_profile_exists:
            if not request.user.is_authenticated():
                # you have to be authenticated to continue
                messages.warning(request, LOGIN_MESSAGE)
                return (login_required(view_profile, login_url=reverse('phonebook:home'))
                        (request, username))

            if not request.user.userprofile.is_vouched:
                # you have to be vouched to continue
                messages.error(request, GET_VOUCHED_MESSAGE)
                return redirect('phonebook:home')

        if not profile_exists or not profile_complete:
            raise Http404

        profile = UserProfile.objects.get(user__username=username)
        profile.set_instance_privacy_level(PUBLIC)
        if request.user.is_authenticated():
            profile.set_instance_privacy_level(
                request.user.userprofile.privacy_level)

        if (request.user.is_authenticated() and request.user.userprofile.is_vouched and
                not profile.can_vouch):
            abuse_report = get_object_or_none(AbuseReport, reporter=request.user.userprofile,
                                              profile=profile)

            if not abuse_report:
                abuse_report = AbuseReport(reporter=request.user.userprofile, profile=profile)

            abuse_form = forms.AbuseReportForm(request.POST or None, instance=abuse_report)
            if abuse_form.is_valid():
                abuse_form.save()
                msg = _(u'Thanks for helping us improve mozillians.org!')
                messages.info(request, msg)
                return redirect('phonebook:profile_view', profile.user.username)

        if (request.user.is_authenticated() and profile.is_vouchable(request.user.userprofile)):

            vouch_form = forms.VouchForm(request.POST or None)
            data['vouch_form'] = vouch_form
            if vouch_form.is_valid():
                # We need to re-fetch profile from database.
                profile = UserProfile.objects.get(user__username=username)
                profile.vouch(request.user.userprofile, vouch_form.cleaned_data['description'])
                # Notify the current user that they vouched successfully.
                msg = _(u'Thanks for vouching for a fellow Mozillian! This user is now vouched!')
                messages.info(request, msg)
                return redirect('phonebook:profile_view', profile.user.username)

    data['shown_user'] = profile.user
    data['profile'] = profile
    data['groups'] = profile.get_annotated_groups()
    data['abuse_form'] = abuse_form

    # Only show pending groups if user is looking at their own profile,
    # or current user is a superuser
    if not (request.user.is_authenticated() and
            (request.user.username == username or request.user.is_superuser)):
        data['groups'] = [grp for grp in data['groups'] if not grp.pending]

    return render(request, 'phonebook/profile.html', data)