Example #1
0
def _check_geni_federation_status(request):
    """
    Checks if a user who authenticated view GENI/OpenID is on the Chameleon Federation
    project on the GENI side. If so, then checks if the user is on the corresponding
    project on the Chameleon side.

    Returns a tuple of boolean values for (on_geni_project, on_chameleon_project)
    """

    geni_project_key = '%s|%s' % (settings.GENI_FEDERATION_PROJECTS['geni']['id'],
                                  settings.GENI_FEDERATION_PROJECTS['geni']['name'])

    on_geni_project = geni_project_key in request.session['openid']['ax']['projects']

    if on_geni_project:
        try:
            fed_proj = Project(settings.GENI_FEDERATION_PROJECTS['chameleon']['id'])
            on_chameleon_project = any(u.username == request.user.username \
                                        for u in fed_proj.get_users())
        except:
            logger.warn('Could not locate Chameleon federation project: %s' % \
                settings.GENI_FEDERATION_PROJECTS['chameleon'])
            on_chameleon_project = False
    else:
        on_chameleon_project = False

    return on_geni_project, on_chameleon_project
Example #2
0
def _check_geni_federation_status(request):
    """
    Checks if a user who authenticated view GENI/OpenID is on the Chameleon Federation
    project on the GENI side. If so, then checks if the user is on the corresponding
    project on the Chameleon side.

    Returns a tuple of boolean values for (on_geni_project, on_chameleon_project)
    """

    geni_project_key = '%s|%s' % (
        settings.GENI_FEDERATION_PROJECTS['geni']['id'],
        settings.GENI_FEDERATION_PROJECTS['geni']['name'])

    on_geni_project = geni_project_key in request.session['openid']['ax'][
        'projects']

    if on_geni_project:
        try:
            fed_proj = Project(
                settings.GENI_FEDERATION_PROJECTS['chameleon']['id'])
            on_chameleon_project = any(u.username == request.user.username \
                                        for u in fed_proj.get_users())
        except:
            logger.warn('Could not locate Chameleon federation project: %s' % \
                settings.GENI_FEDERATION_PROJECTS['chameleon'])
            on_chameleon_project = False
    else:
        on_chameleon_project = False

    return on_geni_project, on_chameleon_project
Example #3
0
def dashboard(request):
    context = {}

    # active projects...
    projects = Project.list(username=request.user)
    context['active_projects'] = [p for p in projects \
                if p.source == 'Chameleon' and \
                any(a.status in ['Active', 'Approved', 'Pending'] for a in p.allocations)]

    # open tickets...
    rt = rtUtil.DjangoRt()
    context['open_tickets'] = rt.getUserTickets(request.user.email)

    # ongoing outages...
    outages = [o for o in Outage.objects.order_by('-end_date', '-start_date') if not o.resolved] # silly ORM quirk
    context['outages'] = outages

    webinars = Webinar.objects.filter(end_date__gte=timezone.now())
    context['webinars'] = webinars

    # federation status...
    if 'openid' in request.session:
        on_geni_project, on_chameleon_project = _check_geni_federation_status(request)
        context['geni_federation'] = {
            'on_geni_project': on_geni_project,
            'on_chameleon_project': on_chameleon_project,
            'geni_project_name': settings.GENI_FEDERATION_PROJECTS['geni']['name'],
            'chameleon_project_name': settings.GENI_FEDERATION_PROJECTS['chameleon']['name'],
        }

    return render(request, 'dashboard.html', context)
Example #4
0
def activate_geni(request):
    fed_proj = Project(settings.GENI_FEDERATION_PROJECTS["chameleon"]["id"])
    on_chameleon_project = any(u.username == request.user for u in fed_proj.get_users())
    if on_chameleon_project:
        messages.info("Your access to the Chameleon-GENI Federation Project is active.")
        return HttpResponseRedirect(reverse("dashboard"))

    if request.method == "POST":
        if request.POST.get("accept_user_terms") == "on":
            fed_proj.add_user(request.user)
            messages.success(request, "Your access to the Chameleon-GENI Federation Project is active.")
            return HttpResponseRedirect(reverse("dashboard"))
        else:
            messages.error(request, "Please agree to Chameleon Acceptable Use Policy before proceeding.")

    context = {
        "geni": settings.GENI_FEDERATION_PROJECTS["geni"],
        "chameleon": settings.GENI_FEDERATION_PROJECTS["chameleon"],
    }
    return render(request, "chameleon_openid/activate_geni.html", context)
Example #5
0
def user_projects(request):
    context = {}

    tas = TASClient()
    user = tas.get_user(username=request.user)
    context['is_pi_eligible'] = user['piEligibility'] == 'Eligible'

    projects = Project.list(username=request.user)
    projects = list(p for p in projects if p.source == 'Chameleon')

    context['projects'] = projects

    return render(request, 'projects/user_projects.html', context)
Example #6
0
def user_projects(request):
    context = {}

    tas = TASClient()
    user = tas.get_user(username=request.user)
    context['is_pi_eligible'] = user['piEligibility'] == 'Eligible'

    projects = Project.list(username=request.user)
    projects = list(p for p in projects if p.source == 'Chameleon')

    context['projects'] = projects

    return render(request, 'projects/user_projects.html', context)
Example #7
0
def user_projects(request):
    context = {}

    tas = TASClient()
    user = tas.get_user(username=request.user)
    context['is_pi_eligible'] = user['piEligibility'] == 'Eligible'

    projects = Project.list(username=request.user)
    projects = list(p for p in projects if p.source == 'Chameleon')

    for proj in projects:
        try:
            extras = ProjectExtras.objects.get(tas_project_id=proj.id)
            proj.__dict__['nickname'] = extras.nickname
        except ProjectExtras.DoesNotExist:
            project_nickname = None

    context['projects'] = projects

    return render(request, 'projects/user_projects.html', context)
Example #8
0
def dashboard(request):
    context = {}

    # active projects...
    projects = Project.list(username=request.user)
    context['active_projects'] = [p for p in projects \
                if p.source == 'Chameleon' and \
                any(a.status in ['Active', 'Approved', 'Pending'] for a in p.allocations)]

    # open tickets...
    rt = rtUtil.DjangoRt()
    context['open_tickets'] = rt.getUserTickets(request.user.email)

    # ongoing outages...
    outages = [
        o for o in Outage.objects.order_by('-end_date', '-start_date')
        if not o.resolved
    ]  # silly ORM quirk
    context['outages'] = outages

    webinars = Webinar.objects.filter(end_date__gte=timezone.now())
    context['webinars'] = webinars

    # federation status...
    if 'openid' in request.session:
        on_geni_project, on_chameleon_project = _check_geni_federation_status(
            request)
        context['geni_federation'] = {
            'on_geni_project':
            on_geni_project,
            'on_chameleon_project':
            on_chameleon_project,
            'geni_project_name':
            settings.GENI_FEDERATION_PROJECTS['geni']['name'],
            'chameleon_project_name':
            settings.GENI_FEDERATION_PROJECTS['chameleon']['name'],
        }

    return render(request, 'dashboard.html', context)
Example #9
0
    def test_bad_id(self, mock_project):
        mock_project.side_effect = Exception('API Error: Object reference not set to an instance of an object.')

        with pytest.raises(Exception) as e:
            p = Project(123)
            assert 'API Error' in str(e.value)
Example #10
0
    def test_get(self, mock_project):
        mock_project.return_value = {
                "allocations": [
                    {
                        "computeAllocated": 50000,
                        "computeRequested": 50000,
                        "computeUsed": 52774.149,
                        "dateRequested": "2014-01-20T19:00:12Z",
                        "dateReviewed": "2014-01-20T19:00:12Z",
                        "decisionSummary": "Project Approved.",
                        "end": "2015-01-20T06:00:00Z",
                        "id": 456,
                        "justification": "Resource justification.",
                        "memoryAllocated": 0,
                        "memoryRequested": 0,
                        "project": "TEST-123456",
                        "projectId": 23567,
                        "requestor": "PI User",
                        "requestorId": 123000,
                        "resource": "Stampede3",
                        "resourceId": 31,
                        "reviewer": None,
                        "reviewerId": 0,
                        "start": "2014-01-21T06:00:00Z",
                        "status": "Active",
                        "storageAllocated": 0,
                        "storageRequested": 0
                    }
                ],
                "chargeCode": "TEST-123456",
                "description": "TEST-123456",
                "field": "Testing",
                "fieldId": 100,
                "gid": 123000,
                "id": 123,
                "pi": {
                    "citizenship": "United States",
                    "citizenshipId": 230,
                    "country": "United States",
                    "countryId": 230,
                    "department": None,
                    "departmentId": 0,
                    "email": "*****@*****.**",
                    "emailConfirmations": [],
                    "firstName": "PI",
                    "id": 17033,
                    "institution": "University College",
                    "institutionId": 999,
                    "lastName": "User",
                    "phone": None,
                    "piEligibility": "Eligible",
                    "source": "Standard",
                    "title": None,
                    "username": "******"
                },
                "piId": 999999,
                "source": "Standard",
                "title": "Lorem ipsum",
                "type": "Research",
                "typeId": 0
            }

        p = Project(123)
        assert p.id == 123
Example #11
0
def view_project(request, project_id):
    try:
        project = Project(project_id)
        if project.source != 'Chameleon':
            raise Http404('The requested project does not exist!')
    except Exception as e:
        logger.error(e)
        raise Http404('The requested project does not exist!')

    if request.POST:
        if 'add_user' in request.POST:
            form = ProjectAddUserForm(request.POST)
            if form.is_valid():
                # try to add user
                try:
                    add_username = form.cleaned_data['username']
                    if project.add_user(add_username):
                        messages.success(request,
                            'User "%s" added to project!' % add_username)
                        form = ProjectAddUserForm()
                except:
                    logger.exception('Failed adding user')
                    form.add_error('username', '')
                    form.add_error('__all__', 'Unable to add user. Confirm that the '
                        'username is correct.')
            else:
                form.add_error('__all__', 'There were errors processing your request. '
                    'Please see below for details.')
        else:
            form = ProjectAddUserForm()

        if 'del_user' in request.POST:
            # try to remove user
            try:
                del_username = request.POST['username']
                if project.remove_user(del_username):
                    messages.success(request, 'User "%s" removed from project' % del_username)
            except:
                logger.exception('Failed removing user')
                messages.error(request, 'An unexpected error occurred while attempting '
                    'to remove this user. Please try again')

    else:
        form = ProjectAddUserForm()

    users = project.get_users()

    if not project_member_or_admin_or_superuser(request.user, project, users):
        raise PermissionDenied

    project.active_allocations = []
    project.pending_allocations = []
    project.rejected_allocations = []
    project.inactive_allocations = []

    for a in project.allocations:
        if a.status == 'Active' and a.resource == 'Chameleon':
            project.active_allocations.append(a)
            project.has_active_allocations = True
        if a.status == 'Pending' and a.resource == 'Chameleon':
            project.pending_allocations.append(a)
            project.has_pending_allocations = True
        if a.status == 'Inactive' and a.resource == 'Chameleon':
            project.inactive_allocations.append(a)
            project.has_inactive_allocations = True
        if a.status == 'Rejected' and a.resource == 'Chameleon':
            project.rejected_allocations.append(a)
            project.has_rejected_allocations = True


        if a.start and isinstance(a.start, basestring):
            a.start = datetime.strptime(a.start, '%Y-%m-%dT%H:%M:%SZ')
        if a.dateRequested:
            if isinstance(a.dateRequested, basestring):
                a.dateRequested = datetime.strptime(a.dateRequested, '%Y-%m-%dT%H:%M:%SZ')
        if a.dateReviewed:
            if isinstance(a.dateReviewed, basestring):
                a.dateReviewed = datetime.strptime(a.dateReviewed, '%Y-%m-%dT%H:%M:%SZ')
        if a.end:
            if isinstance(a.end, basestring):
                a.end = datetime.strptime(a.end, '%Y-%m-%dT%H:%M:%SZ')

            days_left = (a.end - datetime.today()).days
            if days_left >= 0 and days_left <= 90:
                a.up_for_renewal = True
                a.renewal_days = days_left

    return render(request, 'projects/view_project.html', {
        'project': project,
        'users': users,
        'is_pi': request.user.username == project.pi.username,
        'form': form,
    })
Example #12
0
def create_allocation(request, project_id, allocation_id=-1):
    tas = TASClient()

    user = tas.get_user(username=request.user)
    if user['piEligibility'] != 'Eligible':
        messages.error(request,
                       'Only PI Eligible users can request allocations. If you would '
                       'like to request PI Eligibility, please '
                       '<a href="/user/profile/edit/">submit a PI Eligibility '
                       'request</a>.')
        return HttpResponseRedirect(reverse('projects:user_projects'))

    project = Project(project_id)
    allocation = None
    if allocation_id > 0:
        for a in project.allocations:
            if a.id == int(allocation_id):
                allocation = a

    # goofiness that we should clean up later; requires data cleansing
    abstract = project.description
    if '--- Supplemental details ---' in abstract:
        additional = abstract.split('\n\n--- Supplemental details ---\n\n')
        abstract = additional[0]
        additional = additional[1].split('\n\n--- Funding source(s) ---\n\n')
        justification = additional[0]
        if len(additional) > 1:
            funding_source = additional[1]
        else:
            funding_source = ''
    elif allocation:
        justification = allocation.justification
        if '--- Funding source(s) ---' in justification:
            parts = justification.split('\n\n--- Funding source(s) ---\n\n')
            justification = parts[0]
            funding_source = parts[1]
        else:
            funding_source = ''
    else:
        justification = ''
        funding_source = ''

    if request.POST:
        form = AllocationCreateForm(request.POST,
                                    initial={'description': abstract,
                                             'supplemental_details': justification,
                                             'funding_source': funding_source})
        if form.is_valid():
            allocation = form.cleaned_data.copy()
            allocation['computeRequested'] = 20000

            # Also update the project
            project.description = allocation.pop('description', None)

            supplemental_details = allocation.pop('supplemental_details', None)

            logger.error(supplemental_details)
            funding_source = allocation.pop('funding_source', None)

            #if supplemental_details == None:
            #    raise forms.ValidationError("Justifcation is required")
            # This is required
            if not supplemental_details:
                supplemental_details = '(none)'

            logger.error(supplemental_details)

            if funding_source:
                allocation['justification'] = '%s\n\n--- Funding source(s) ---\n\n%s' % (
                    supplemental_details, funding_source)
            else:
                allocation['justification'] = supplemental_details

            allocation['projectId'] = project_id
            allocation['requestorId'] = tas.get_user(username=request.user)['id']
            allocation['resourceId'] = '39'

            if allocation_id > 0:
                allocation['id'] = allocation_id

            try:
                logger.info('Submitting allocation request for project %s: %s' %
                            (project.id, allocation))
                updated_project = tas.edit_project(project.as_dict())
                tas.create_allocation(allocation)
                messages.success(request, 'Your allocation request has been submitted!')
                return HttpResponseRedirect(
                    reverse('projects:view_project', args=[updated_project['id']]))
            except:
                logger.exception('Error creating allocation')
                form.add_error('__all__',
                               'An unexpected error occurred. Please try again')
        else:
            form.add_error('__all__',
                           'There were errors processing your request. '
                           'Please see below for details.')
    else:
        form = AllocationCreateForm(initial={'description': abstract,
                                             'supplemental_details': justification,
                                             'funding_source': funding_source})
    context = {
        'form': form,
        'project': project,
        'alloc_id': allocation_id,
        'alloc': allocation
    }
    return render(request, 'projects/create_allocation.html', context)
Example #13
0
def view_project(request, project_id):
    try:
        project = Project(project_id)
        if project.source != 'Chameleon':
            raise Http404('The requested project does not exist!')
    except Exception as e:
        logger.error(e)
        raise Http404('The requested project does not exist!')

    if request.POST:
        if 'add_user' in request.POST:
            form = ProjectAddUserForm(request.POST)
            if form.is_valid():
                # try to add user
                try:
                    add_username = form.cleaned_data['username']
                    if project.add_user(add_username):
                        messages.success(
                            request,
                            'User "%s" added to project!' % add_username)
                        form = ProjectAddUserForm()
                except:
                    logger.exception('Failed adding user')
                    form.add_error('username', '')
                    form.add_error(
                        '__all__', 'Unable to add user. Confirm that the '
                        'username is correct.')
            else:
                form.add_error(
                    '__all__', 'There were errors processing your request. '
                    'Please see below for details.')
        else:
            form = ProjectAddUserForm()

        if 'del_user' in request.POST:
            # try to remove user
            try:
                del_username = request.POST['username']
                if project.remove_user(del_username):
                    messages.success(
                        request,
                        'User "%s" removed from project' % del_username)
            except:
                logger.exception('Failed removing user')
                messages.error(
                    request, 'An unexpected error occurred while attempting '
                    'to remove this user. Please try again')

    else:
        form = ProjectAddUserForm()

    users = project.get_users()

    if not project_member_or_admin_or_superuser(request.user, project, users):
        raise PermissionDenied

    project.active_allocations = []
    project.approved_allocations = []
    project.pending_allocations = []
    project.rejected_allocations = []
    project.inactive_allocations = []

    for a in project.allocations:
        if a.status == 'Active' and a.resource == 'Chameleon':
            project.active_allocations.append(a)
            project.has_active_allocations = True
        if a.status == 'Approved' and a.resource == 'Chameleon':
            project.approved_allocations.append(a)
            project.has_approved_allocations = True
        if a.status == 'Pending' and a.resource == 'Chameleon':
            project.pending_allocations.append(a)
            project.has_pending_allocations = True
        if a.status == 'Inactive' and a.resource == 'Chameleon':
            project.inactive_allocations.append(a)
            project.has_inactive_allocations = True
        if a.status == 'Rejected' and a.resource == 'Chameleon':
            project.rejected_allocations.append(a)
            project.has_rejected_allocations = True

        if a.start and isinstance(a.start, basestring):
            a.start = datetime.strptime(a.start, '%Y-%m-%dT%H:%M:%SZ')
        if a.dateRequested:
            if isinstance(a.dateRequested, basestring):
                a.dateRequested = datetime.strptime(a.dateRequested,
                                                    '%Y-%m-%dT%H:%M:%SZ')
        if a.dateReviewed:
            if isinstance(a.dateReviewed, basestring):
                a.dateReviewed = datetime.strptime(a.dateReviewed,
                                                   '%Y-%m-%dT%H:%M:%SZ')
        if a.end:
            if isinstance(a.end, basestring):
                a.end = datetime.strptime(a.end, '%Y-%m-%dT%H:%M:%SZ')

            days_left = (a.end - datetime.today()).days
            if days_left >= 0 and days_left <= 90:
                a.up_for_renewal = True
                a.renewal_days = days_left

    return render(
        request, 'projects/view_project.html', {
            'project': project,
            'users': users,
            'is_pi': request.user.username == project.pi.username,
            'form': form,
        })
Example #14
0
def create_allocation(request, project_id, allocation_id=-1):
    tas = TASClient()

    user = tas.get_user(username=request.user)
    if user['piEligibility'] != 'Eligible':
        messages.error(
            request,
            'Only PI Eligible users can request allocations. If you would '
            'like to request PI Eligibility, please '
            '<a href="/user/profile/edit/">submit a PI Eligibility '
            'request</a>.')
        return HttpResponseRedirect(reverse('projects:user_projects'))

    project = Project(project_id)
    allocation = None
    if allocation_id > 0:
        for a in project.allocations:
            if a.id == int(allocation_id):
                allocation = a

    # goofiness that we should clean up later; requires data cleansing
    abstract = project.description
    if '--- Supplemental details ---' in abstract:
        additional = abstract.split('\n\n--- Supplemental details ---\n\n')
        abstract = additional[0]
        additional = additional[1].split('\n\n--- Funding source(s) ---\n\n')
        justification = additional[0]
        if len(additional) > 1:
            funding_source = additional[1]
        else:
            funding_source = ''
    elif allocation:
        justification = allocation.justification
        if '--- Funding source(s) ---' in justification:
            parts = justification.split('\n\n--- Funding source(s) ---\n\n')
            justification = parts[0]
            funding_source = parts[1]
        else:
            funding_source = ''
    else:
        justification = ''
        funding_source = ''

    if request.POST:
        form = AllocationCreateForm(request.POST,
                                    initial={
                                        'description': abstract,
                                        'supplemental_details': justification,
                                        'funding_source': funding_source
                                    })
        if form.is_valid():
            allocation = form.cleaned_data.copy()
            allocation['computeRequested'] = 20000

            # Also update the project
            project.description = allocation.pop('description', None)

            supplemental_details = allocation.pop('supplemental_details', None)

            logger.error(supplemental_details)
            funding_source = allocation.pop('funding_source', None)

            #if supplemental_details == None:
            #    raise forms.ValidationError("Justifcation is required")
            # This is required
            if not supplemental_details:
                supplemental_details = '(none)'

            logger.error(supplemental_details)

            if funding_source:
                allocation[
                    'justification'] = '%s\n\n--- Funding source(s) ---\n\n%s' % (
                        supplemental_details, funding_source)
            else:
                allocation['justification'] = supplemental_details

            allocation['projectId'] = project_id
            allocation['requestorId'] = tas.get_user(
                username=request.user)['id']
            allocation['resourceId'] = '39'

            if allocation_id > 0:
                allocation['id'] = allocation_id

            try:
                logger.info(
                    'Submitting allocation request for project %s: %s' %
                    (project.id, allocation))
                updated_project = tas.edit_project(project.as_dict())
                tas.create_allocation(allocation)
                messages.success(
                    request, 'Your allocation request has been submitted!')
                return HttpResponseRedirect(
                    reverse('projects:view_project',
                            args=[updated_project['id']]))
            except:
                logger.exception('Error creating allocation')
                form.add_error(
                    '__all__',
                    'An unexpected error occurred. Please try again')
        else:
            form.add_error(
                '__all__', 'There were errors processing your request. '
                'Please see below for details.')
    else:
        form = AllocationCreateForm(
            initial={
                'description': abstract,
                'supplemental_details': justification,
                'funding_source': funding_source
            })
    context = {
        'form': form,
        'project': project,
        'alloc_id': allocation_id,
        'alloc': allocation
    }
    return render(request, 'projects/create_allocation.html', context)
Example #15
0
def view_project(request, project_id):
    try:
        project = Project(project_id)
        if project.source != 'Chameleon':
            raise Http404('The requested project does not exist!')
    except Exception as e:
        logger.error(e)
        raise Http404('The requested project does not exist!')

    form = ProjectAddUserForm()
    nickname_form = EditNicknameForm()
    if request.POST:
        if 'add_user' in request.POST:
            form = ProjectAddUserForm(request.POST)
            if form.is_valid():
                # try to add user
                try:
                    add_username = form.cleaned_data['username']
                    if project.add_user(add_username):
                        messages.success(request,
                            'User "%s" added to project!' % add_username)
                        form = ProjectAddUserForm()
                except:
                    logger.exception('Failed adding user')
                    form.add_error('username', '')
                    form.add_error('__all__', 'Unable to add user. Confirm that the '
                        'username is correct.')
            else:
                form.add_error('__all__', 'There were errors processing your request. '
                    'Please see below for details.')
        elif 'nickname' in request.POST:
            nickname_form = edit_nickname(request, project_id)
        else:
            form = ProjectAddUserForm()

        if 'del_user' in request.POST:
            # try to remove user
            try:
                del_username = request.POST['username']
                if project.remove_user(del_username):
                    messages.success(request, 'User "%s" removed from project' % del_username)
            except:
                logger.exception('Failed removing user')
                messages.error(request, 'An unexpected error occurred while attempting '
                    'to remove this user. Please try again')

    users = project.get_users()

    if not project_member_or_admin_or_superuser(request.user, project, users):
        raise PermissionDenied

    project.active_allocations = []
    project.approved_allocations = []
    project.pending_allocations = []
    project.rejected_allocations = []
    project.inactive_allocations = []

    for a in project.allocations:
        if a.status == 'Active' and a.resource == 'Chameleon':
            project.active_allocations.append(a)
            project.has_active_allocations = True
        if a.status == 'Approved' and a.resource == 'Chameleon':
            project.approved_allocations.append(a)
            project.has_approved_allocations = True
        if a.status == 'Pending' and a.resource == 'Chameleon':
            project.pending_allocations.append(a)
            project.has_pending_allocations = True
        if a.status == 'Inactive' and a.resource == 'Chameleon':
            project.inactive_allocations.append(a)
            project.has_inactive_allocations = True
        if a.status == 'Rejected' and a.resource == 'Chameleon':
            project.rejected_allocations.append(a)
            project.has_rejected_allocations = True


        if a.start and isinstance(a.start, basestring):
            a.start = datetime.strptime(a.start, '%Y-%m-%dT%H:%M:%SZ')
        if a.dateRequested:
            if isinstance(a.dateRequested, basestring):
                a.dateRequested = datetime.strptime(a.dateRequested, '%Y-%m-%dT%H:%M:%SZ')
        if a.dateReviewed:
            if isinstance(a.dateReviewed, basestring):
                a.dateReviewed = datetime.strptime(a.dateReviewed, '%Y-%m-%dT%H:%M:%SZ')
        if a.end:
            if isinstance(a.end, basestring):
                a.end = datetime.strptime(a.end, '%Y-%m-%dT%H:%M:%SZ')

            days_left = (a.end - datetime.today()).days
            if days_left >= 0 and days_left <= 90:
                a.up_for_renewal = True
                a.renewal_days = days_left

    try:
        extras = ProjectExtras.objects.get(tas_project_id=project_id)
        project_nickname = extras.nickname
    except ProjectExtras.DoesNotExist:
        project_nickname = None

    user_mashup = []
    for u in users:
        if u.role == 'PI': # Exclude PI from member list
            continue
        user = {}
        user['username'] = u.username
        user['role'] = u.role
        try:
            portal_user = User.objects.get(username=u.username)
            user['email'] = portal_user.email
            user['first_name'] = portal_user.first_name
            user['last_name'] = portal_user.last_name
        except User.DoesNotExist:
            logger.info('user: '******' not found')
        user_mashup.append(user)

    return render(request, 'projects/view_project.html', {
        'project': project,
        'project_nickname': project_nickname,
        'users': user_mashup,
        'is_pi': request.user.username == project.pi.username,
        'form': form,
        'nickname_form': nickname_form,
    })