Commit 2f131faf by Clinton Blackburn

Merge pull request #10961 from edx/release

Merging patch/2015-12-11
parents cd9fe577 ca0e0b97
......@@ -782,14 +782,10 @@
}
.credit-action {
.credit-msg {
@include float(left);
width: flex-grid(10, 12);
}
.credit-btn {
@extend %btn-pl-yellow-base;
@include float(right);
margin-right: 5px;
background-image: none ;
text-shadow: none;
box-shadow: none;
......
<%page args="credit_status" />
<%!
import datetime
import pytz
from django.utils.translation import ugettext as _
from util.date_utils import get_default_time_display
%>
<%namespace name='static' file='../static_content.html'/>
% if credit_status["provider_name"]:
<% provider_link='<a href="{}" target="_blank">{}</a>'.format(credit_status["provider_status_url"], credit_status["provider_name"]) %>
% endif
% if credit_status["eligible"]:
<%
provider_link = '<a href="{href}" target="_blank">{name}</a>'.format(
href=credit_status["provider_status_url"],
name=credit_status["provider_name"])
error = credit_status['error']
status = 'eligible'
# Translators: provider_name is the name of a credit provider or university (e.g. State University)
credit_msg = _("You have completed this course and are eligible to purchase course credit. Select <strong>Get Credit</strong> to get started.")
credit_msg_class = "credit-eligibility-msg"
credit_btn_class = "purchase-credit-btn"
credit_btn_label = _("Get Credit")
credit_btn_href = '{root}/credit/checkout/{course_id}/'.format(
root=settings.ECOMMERCE_PUBLIC_URL_ROOT,
course_id=credit_status['course_key'])
if credit_status["purchased"]:
request_status = credit_status["request_status"]
if request_status is None:
# Learner must initiate the credit request
# Translators: link_to_provider_site is a link to an external webpage. The text of the link will be the name of a credit provider, such as 'State University' or 'Happy Fun Company'.
credit_msg = _("Thank you for your payment. To receive course credit, you must now request credit "
"at the {link_to_provider_site} website. Select <b>Request Credit</b> to get started.").format(
link_to_provider_site=provider_link,
)
credit_msg_class = "credit-request-pending-msg"
credit_btn_label = _("Request Credit")
credit_btn_class = 'pending-credit-btn'
elif request_status == 'pending':
# Request received but not reviewed
## Translators: provider_name is the name of a credit provider or university (e.g. State University)
credit_msg = _("{provider_name} has received your course credit request. We will update you when credit processing is complete.").format(provider_name=credit_status["provider_name"])
credit_msg_class = "credit-request-pending-msg"
credit_btn_label = _("View Details")
credit_btn_class = 'pending-credit-btn'
elif request_status == 'approved':
# Credit granted!
# Translators: link_to_provider_site is a link to an external webpage. The text of the link will be the name of a credit provider, such as 'State University' or 'Happy Fun Company'. provider_name is the name of credit provider.
credit_msg = _("<b>Congratulations!</b> {provider_name} has approved your request for course credit. To see your course credit, visit the {link_to_provider_site} website.").format(
provider_name=credit_status["provider_name"],
link_to_provider_site=provider_link,
)
credit_msg_class = "credit-request-approved-msg"
credit_btn_href = credit_status['provider_status_url']
credit_btn_label = _("View Credit")
elif request_status == 'rejected':
# REJECTED (by the credit provider)!
## Translators: link_to_provider_site is a link to an external webpage. The text of the link will be the name of a credit provider, such as 'State University' or 'Happy Fun Company'. provider_name is the name of credit provider.
credit_msg = _("{provider_name} did not approve your request for course credit. For more information, contact {link_to_provider_site} directly.").format(
provider_name=credit_status["provider_name"],
link_to_provider_site=provider_link,
)
credit_msg_class = "credit-request-rejected-msg"
credit_btn_label = None
%>
<div class="message message-status is-shown credit-message">
<p class="message-copy is-hidden credit-error-msg" data-credit-error="${credit_status['error']}">
${_("An error occurred with this transaction. For help, contact {support_email}.").format(
support_email=u'<a href="mailto:{address}">{address}</a>'.format(
address=settings.DEFAULT_FEEDBACK_EMAIL
)
support_email=u'<a href="mailto:{address}">{address}</a>'.format(
address=settings.DEFAULT_FEEDBACK_EMAIL
)
)}
</p>
<div class="credit-action">
% if not credit_status["purchased"] and not credit_status["error"] :
<p class="message-copy credit-msg credit-eligibility-msg">
## Translators: provider_name is the name of a credit provider or university (e.g. State University)
${_("You have completed this course and are eligible to purchase course credit. Select <strong>Get Credit</strong> to get started.")}
</p>
<div class="purchase_credit">
<a class="btn credit-btn purchase-credit-btn" href="${settings.ECOMMERCE_PUBLIC_URL_ROOT}/credit/checkout/${credit_status['course_key']}" target="_blank" data-course-key="${credit_status['course_key']}">${_("Get Credit")}</a>
</div>
% elif credit_status["request_status"] in [None, "pending"] and not credit_status["error"]:
% if credit_status["request_status"] == "pending":
<p class="message-copy credit-msg credit-request-pending-msg">
## Translators: provider_name is the name of a credit provider or university (e.g. State University)
${_("{provider_name} has received your course credit request. We will update you when credit processing is complete.").format(
provider_name=credit_status["provider_name"],
)
}
</p>
% elif credit_status["request_status"] is None:
<p class="message-copy credit-msg credit-request-pending-msg">
## Translators: link_to_provider_site is a link to an external webpage. The text of the link will be the name of a
## credit provider, such as 'State University' or 'Happy Fun Company'.
${_("Thank you for your payment. To receive course credit, you must now request credit at the {link_to_provider_site} website. Select <b>Request Credit</b> to get started.").format(
link_to_provider_site=provider_link,
)
}
</p>
<div class="credit-action">
% if credit_btn_label:
<a class="btn credit-btn ${credit_btn_class}" href="${credit_btn_href}" target="_blank" data-course-key="${credit_status['course_key']}" data-user="${user.username}" data-provider="${credit_status['provider_id']}">
${credit_btn_label}
</a>
% endif
<a class="btn credit-btn access-credit-btn" href="${credit_status['provider_status_url']}" target="_blank">${_("View Details")}</a>
% elif credit_status["request_status"] == "approved" and not credit_status["error"] :
<p class="message-copy credit-msg credit-request-approved-msg">
## Translators: link_to_provider_site is a link to an external webpage. The text of the link will be the name of a
## credit provider, such as 'State University' or 'Happy Fun Company'. provider_name is the name of credit provider.
${_("<b>Congratulations!</b> {provider_name} has approved your request for course credit. To see your course credit, visit the {link_to_provider_site} website.").format(
provider_name=credit_status["provider_name"],
link_to_provider_site=provider_link,
)
}
</p>
<a class="btn credit-btn access-credit-btn" href="${credit_status['provider_status_url']}" target="_blank">${_("View Credit")}</a>
% elif credit_status["request_status"] == "rejected" and not credit_status["error"] :
<p class="message-copy credit-msg credit-request-rejected-msg">
## Translators: link_to_provider_site is a link to an external webpage. The text of the link will be the name of a
## credit provider, such as 'State University' or 'Happy Fun Company'. provider_name is the name of credit provider.
${_("{provider_name} did not approve your request for course credit. For more information, contact {link_to_provider_site} directly.").format(
provider_name=credit_status["provider_name"],
link_to_provider_site=provider_link,
)
}
</p>
% endif
<div class="message-copy credit-msg ${credit_msg_class}">${credit_msg}</div>
</div>
</div>
% endif
......@@ -3,8 +3,8 @@ API library for Django REST Framework permissions-oriented workflows
"""
from django.conf import settings
from rest_framework import permissions
from django.http import Http404
from rest_framework import permissions
from student.roles import CourseStaffRole
......@@ -13,6 +13,7 @@ class ApiKeyHeaderPermission(permissions.BasePermission):
"""
Django REST Framework permissions class used to manage API Key integrations
"""
def has_permission(self, request, view):
"""
Check for permissions by matching the configured API key and header
......@@ -35,8 +36,9 @@ class ApiKeyHeaderPermissionIsAuthenticated(ApiKeyHeaderPermission, permissions.
See ApiKeyHeaderPermission for more information how the API key portion is implemented.
"""
def has_permission(self, request, view):
#TODO We can optimize this later on when we know which of these methods is used more often.
# TODO We can optimize this later on when we know which of these methods is used more often.
api_permissions = ApiKeyHeaderPermission.has_permission(self, request, view)
is_authenticated_permissions = permissions.IsAuthenticated.has_permission(self, request, view)
return api_permissions or is_authenticated_permissions
......@@ -46,6 +48,7 @@ class IsUserInUrl(permissions.BasePermission):
"""
Permission that checks to see if the request user matches the user in the URL.
"""
def has_permission(self, request, view):
"""
Returns true if the current request is by the user themselves.
......@@ -65,6 +68,7 @@ class IsUserInUrlOrStaff(IsUserInUrl):
"""
Permission that checks to see if the request user matches the user in the URL or has is_staff access.
"""
def has_permission(self, request, view):
if request.user.is_staff:
return True
......@@ -76,6 +80,7 @@ class IsStaffOrReadOnly(permissions.BasePermission):
"""Permission that checks to see if the user is global or course
staff, permitting only read-only access if they are not.
"""
def has_object_permission(self, request, view, obj):
return (request.user.is_staff or
CourseStaffRole(obj.course_id).has_user(request.user) or
......@@ -87,9 +92,12 @@ class IsStaffOrOwner(permissions.BasePermission):
Permission that allows access to admin users or the owner of an object.
The owner is considered the User object represented by obj.user.
"""
def has_object_permission(self, request, view, obj):
return request.user.is_staff or obj.user == request.user
def has_permission(self, request, view):
user = request.user
return user.is_staff or (user.username == request.GET.get('username'))
return user.is_staff \
or (user.username == request.GET.get('username')) \
or (user.username == getattr(request, 'data', {}).get('username'))
""" Tests for API permissions classes. """
import ddt
from django.test import TestCase, RequestFactory
from openedx.core.lib.api.permissions import IsStaffOrOwner
......@@ -10,8 +12,10 @@ class TestObject(object):
user = None
@ddt.ddt
class IsStaffOrOwnerTests(TestCase):
""" Tests for IsStaffOrOwner permission class. """
def setUp(self):
super(IsStaffOrOwnerTests, self).setUp()
self.permission = IsStaffOrOwner()
......@@ -50,13 +54,24 @@ class IsStaffOrOwnerTests(TestCase):
self.request.user = UserFactory.create(is_staff=True)
self.assertTrue(self.permission.has_permission(self.request, None))
def test_has_permission_as_owner(self):
""" Owners always have permission. """
def test_has_permission_as_owner_with_get(self):
""" Owners always have permission to make GET actions. """
user = UserFactory.create()
request = RequestFactory().get('/?username={}'.format(user.username))
request.user = user
self.assertTrue(self.permission.has_permission(request, None))
@ddt.data('patch', 'post', 'put')
def test_has_permission_as_owner_with_edit(self, action):
""" Owners always have permission to edit. """
user = UserFactory.create()
data = {'username': user.username}
request = getattr(RequestFactory(), action)('/', data, format='json')
request.user = user
request.data = data # Note (CCB): This is a hack that should be fixed. (ECOM-3171)
self.assertTrue(self.permission.has_permission(request, None))
def test_has_permission_as_non_owner(self):
""" Non-owners should not have permission. """
user = UserFactory.create()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment