Skip to content

Commit

Permalink
Merge pull request #378 from ucb-rit/develop
Browse files Browse the repository at this point in the history
Add a request hub, a billing module, management commands, feature flags, error logging/tracking, minor enhancements/bug fixes
  • Loading branch information
matthew-li authored Mar 11, 2022
2 parents 0034106 + 574f8be commit 34a7d61
Show file tree
Hide file tree
Showing 70 changed files with 3,623 additions and 765 deletions.
28 changes: 28 additions & 0 deletions bootstrap/ansible/cf_mybrc_settings_template.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,31 @@ API_LOG_PATH = '{{ log_path }}/{{ api_log_file }}'

# A list of admin email addresses to CC when certain requests are approved.
REQUEST_APPROVAL_CC_LIST = {{ request_approval_cc_list }}

# Use a secure cookie for the session cookie (HTTPS only).
{% if ssl_enabled | bool %}
SESSION_COOKIE_SECURE = True
{% else %}
SESSION_COOKIE_SECURE = False
{% endif %}

# Configure Sentry.
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.logging import ignore_logger


{% if sentry_dsn|length > 0 %}
SENTRY_DSN = '{{ sentry_dsn.strip() }}'
{% else %}
SENTRY_DSN = ''
{% endif %}
if SENTRY_DSN:
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[DjangoIntegration()],
traces_sample_rate=0.01,
send_default_pii=True)
# Ignore noisy loggers.
ignore_logger('coldfront.api')
ignore_logger('coldfront.core.utils.middleware')
3 changes: 3 additions & 0 deletions bootstrap/ansible/main.copyme
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ email_subject_prefix: '[MyBRC-User-Portal]'

google_sheets_credentials: '/tmp/credentials.json'

# The URL of the Sentry instance to send errors to.
sentry_dsn: ""

#####################################
#STAGING SETTINGS
#####################################
Expand Down
3 changes: 3 additions & 0 deletions bootstrap/development/main.copyme
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ email_subject_prefix: "[MyBRC-User-Portal]"

google_sheets_credentials: /tmp/credentials.json

# The URL of the Sentry instance to send errors to.
sentry_dsn: ""

###############################################################################
# dev_settings
###############################################################################
Expand Down
22 changes: 20 additions & 2 deletions coldfront/config/local_settings.py.sample
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ if DEBUG is False and SECRET_KEY == 'vtri&lztlbinerr4+yg1yzm23ez@+ub6=4*63z1%d!)
# This should be set to True in production when using HTTPS
SESSION_COOKIE_SECURE = False

# Sessions should last for one hour.
SESSION_COOKIE_AGE = 60 * 60

# ------------------------------------------------------------------------------
# myBRC settings
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -335,9 +338,9 @@ LOCAL_SETTINGS_EXPORT += [

# XDMOD_API_URL = 'http://localhost'

# ------------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Enable myBRC REST API
# ------------------------------------------------------------------------------
# -----------------------------------------------------------------------------
EXTRA_APPS += [
'rest_framework',
'django_filters',
Expand Down Expand Up @@ -381,6 +384,21 @@ EMAIL_VERIFICATION_TIMEOUT = 24 * 60 * 60
# The credentials needed to read from Google Sheets.
GOOGLE_OAUTH2_KEY_FILE = "/tmp/credentials.json"

#------------------------------------------------------------------------------
# django-flags settings
#------------------------------------------------------------------------------

FLAGS = {
'LRC_ONLY': [],
}

# -----------------------------------------------------------------------------
# Miscellaneous settings
# -----------------------------------------------------------------------------
EXTRA_MIDDLEWARE += [
'coldfront.core.utils.middleware.ExceptionMiddleware',
]

#------------------------------------------------------------------------------
# Deployment-specific settings
#------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions coldfront/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@
# 'coldfront.core.publication',
# 'coldfront.core.research_output',
'coldfront.core.statistics',
'coldfront.core.billing',
]

# Savio-specific Additional Apps
INSTALLED_APPS += [
'flags',
'formtools',
]

Expand Down
37 changes: 23 additions & 14 deletions coldfront/core/allocation/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class AllocationAdmin(SimpleHistoryAdmin):
'project', 'justification', 'created', 'modified',)
fields_change = ('project', 'resources', 'quantity', 'justification',
'status', 'start_date', 'end_date', 'description', 'created', 'modified', 'is_locked')
list_display = ('pk', 'project_title', 'project_pis', 'resource', 'quantity',
list_display = ('pk', 'project', 'project_pis', 'resource', 'quantity',
'justification', 'start_date', 'end_date', 'status', 'created', 'modified', )
inlines = [AllocationUserInline,
AllocationAttributeInline,
Expand All @@ -76,8 +76,8 @@ def resource(self, obj):
def project_pis(self, obj):
return ', '.join(obj.project.pis().values_list('username', flat=True))

def project_title(self, obj):
return textwrap.shorten(obj.project.title, width=50)
def project(self, obj):
return obj.project.name

def get_fields(self, request, obj):
if obj is None:
Expand Down Expand Up @@ -156,8 +156,8 @@ def queryset(self, request, queryset):
@admin.register(AllocationAttribute)
class AllocationAttributeAdmin(SimpleHistoryAdmin):
readonly_fields_change = (
'allocation', 'allocation_attribute_type', 'created', 'modified', 'project_title')
fields_change = ('project_title', 'allocation',
'allocation', 'allocation_attribute_type', 'created', 'modified', 'project')
fields_change = ('project', 'allocation',
'allocation_attribute_type', 'value', 'created', 'modified',)
list_display = ('pk', 'project', 'pis', 'resource', 'allocation_status',
'allocation_attribute_type', 'value', 'usage', 'created', 'modified',)
Expand All @@ -168,6 +168,7 @@ class AllocationAttributeAdmin(SimpleHistoryAdmin):
'allocation__allocationuser__user__first_name',
'allocation__allocationuser__user__last_name',
'allocation__allocationuser__user__username',
'allocation__project__name',
)

def usage(self, obj):
Expand All @@ -190,7 +191,7 @@ def pis(self, obj):
for pi_user in pi_users])

def project(self, obj):
return textwrap.shorten(obj.allocation.project.title, width=50)
return obj.allocation.project.name

def project_title(self, obj):
return obj.allocation.project.title
Expand Down Expand Up @@ -250,7 +251,7 @@ def project_pis(self, obj):
return ', '.join(project.pis().values_list('username', flat=True))

def project(self, obj):
return textwrap.shorten(obj.allocation.project.title, width=50)
return obj.allocation.project.name

def get_fields(self, request, obj):
if obj is None:
Expand Down Expand Up @@ -334,12 +335,14 @@ class AllocationAttributeUsageAdmin(SimpleHistoryAdmin):
fields = ('allocation_attribute', 'value',)
list_filter = ('allocation_attribute__allocation_attribute_type',
'allocation_attribute__allocation__resources', ValueFilter, )
search_fields = ('allocation_attribute__allocation__resources__name',
'allocation_attribute__allocation__project__name')

def resource(self, obj):
return obj.allocation_attribute.allocation.resources.first().name

def project(self, obj):
return obj.allocation_attribute.allocation.project.title
return obj.allocation_attribute.allocation.project.name

def project_pis(self, obj):
project = obj.allocation_attribute.allocation.project
Expand All @@ -359,8 +362,8 @@ class AllocationUserAttributeUsageInline(admin.TabularInline):
@admin.register(AllocationUserAttribute)
class AllocationUserAttributeAdmin(SimpleHistoryAdmin):
readonly_fields_change = (
'allocation_user', 'allocation', 'allocation_attribute_type', 'created', 'modified', 'project_title')
fields_change = ('project_title', 'allocation', 'allocation_user',
'allocation_user', 'allocation', 'allocation_attribute_type', 'created', 'modified', 'project')
fields_change = ('project', 'allocation', 'allocation_user',
'allocation_attribute_type', 'value', 'created', 'modified',)
list_display = ('pk', 'user', 'project', 'resource',
'allocation_attribute_type', 'value', 'created', 'modified',)
Expand All @@ -370,7 +373,8 @@ class AllocationUserAttributeAdmin(SimpleHistoryAdmin):
search_fields = (
'allocation_user__user__first_name',
'allocation_user__user__last_name',
'allocation_user__user__username'
'allocation_user__user__username',
'allocation_user__allocation__project__name',
)

def resource(self, obj):
Expand All @@ -387,7 +391,7 @@ def pis(self, obj):
for pi_user in pi_users])

def project(self, obj):
return textwrap.shorten(obj.allocation.project.title, width=50)
return obj.allocation.project.name

def user(self, obj):
return textwrap.shorten(obj.allocation_user.user.username, width=50)
Expand All @@ -410,15 +414,20 @@ def get_readonly_fields(self, request, obj):

@admin.register(AllocationUserAttributeUsage)
class AllocationUserAttributeUsageAdmin(SimpleHistoryAdmin):
list_display = ('allocation_user_attribute', 'project',
list_display = ('allocation_user_attribute', 'user', 'project',
'resource', 'value',)
readonly_fields = ('allocation_user_attribute',)
fields = ('allocation_user_attribute', 'value',)
list_filter = ('allocation_user_attribute__allocation_attribute_type',
'allocation_user_attribute__allocation__resources', ValueFilter, )
search_fields = ('allocation_user_attribute__allocation__project__name',
'allocation_user_attribute__allocation_user__user__username')

def resource(self, obj):
return obj.allocation_user_attribute.allocation.resources.first().name

def project(self, obj):
return obj.allocation_user_attribute.allocation.project.title
return obj.allocation_user_attribute.allocation.project.name

def user(self, obj):
return obj.allocation_user_attribute.allocation_user.user.username
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
AllocationStatusChoice,
AllocationUserStatusChoice)

from flags.state import flag_enabled


class Command(BaseCommand):
help = 'Add default allocation related choices'
Expand Down Expand Up @@ -55,6 +57,20 @@ def handle(self, *args, **options):
AllocationAttributeType.objects.filter(
name='Cluster Account Status').update(is_unique=True)

# Create LRC-only AllocationAttributeTypes.
if flag_enabled('LRC_ONLY'):
# The primary key of the BillingActivity object to be treated as
# the default for the Allocation.
AllocationAttributeType.objects.update_or_create(
attribute_type=AttributeType.objects.get(name='Int'),
name='Billing Activity',
defaults={
'has_usage': False,
'is_required': False,
'is_unique': True,
'is_private': True,
})

choices = [
'Under Review',
'Approved',
Expand Down
Loading

0 comments on commit 34a7d61

Please sign in to comment.