1 ##############################################################################
2 # Copyright (c) 2016 Max Breitenfeldt and others.
3 # Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others.
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
14 from django.utils import timezone
15 from django.contrib import messages
16 from django.contrib.auth import logout
17 from django.contrib.auth.decorators import login_required
18 from django.contrib.auth.mixins import LoginRequiredMixin
19 from django.contrib.auth.models import User
20 from django.urls import reverse
21 from django.http import HttpResponse
22 from django.shortcuts import get_object_or_404
23 from django.utils.decorators import method_decorator
24 from django.views.generic import RedirectView, TemplateView, UpdateView
25 from django.shortcuts import render
26 from rest_framework.authtoken.models import Token
27 from mozilla_django_oidc.auth import OIDCAuthenticationBackend
30 from account.forms import AccountSettingsForm
31 from account.models import UserProfile
32 from booking.models import Booking
33 from resource_inventory.models import ResourceTemplate, Image
36 @method_decorator(login_required, name='dispatch')
37 class AccountSettingsView(UpdateView):
39 form_class = AccountSettingsForm
40 template_name_suffix = '_update_form'
42 def get_success_url(self):
43 messages.add_message(self.request, messages.INFO,
47 def get_object(self, queryset=None):
48 return self.request.user.userprofile
50 def get_context_data(self, **kwargs):
51 token, created = Token.objects.get_or_create(user=self.request.user)
52 context = super(AccountSettingsView, self).get_context_data(**kwargs)
53 context.update({'title': "Settings", 'token': token})
57 class MyOIDCAB(OIDCAuthenticationBackend):
58 def filter_users_by_claims(self, claims):
60 Checks to see if user exists and create user if not
62 Linux foundation does not allow users to change their
63 username, so chose to match users based on their username.
64 If this changes we will need to match users based on some
67 username = claims.get(os.environ.get('CLAIMS_ENDPOINT') + 'username')
70 return HttpResponse('No username provided, contact support.')
73 # For literally no (good) reason user needs to be a queryset
74 user = User.objects.filter(username=username)
76 except User.DoesNotExist:
77 return self.UserModel.objects.none()
79 def create_user(self, claims):
80 """ This creates a user and user profile"""
81 user = super(MyOIDCAB, self).create_user(claims)
82 user.username = claims.get(os.environ['CLAIMS_ENDPOINT'] + 'username')
87 up.email_addr = claims.get('email')
91 def update_user(self, user, claims):
92 """ If their account has different email, change the email """
93 up = UserProfile.objects.get(user=user)
94 up.email_addr = claims.get('email')
99 class OIDCLoginView(RedirectView):
100 def get_redirect_url(self, *args, **kwargs):
101 return reverse('oidc_authentication_init')
104 class LogoutView(LoginRequiredMixin, RedirectView):
105 def get_redirect_url(self, *args, **kwargs):
110 @method_decorator(login_required, name='dispatch')
111 class UserListView(TemplateView):
112 template_name = "account/user_list.html"
114 def get_context_data(self, **kwargs):
115 users = UserProfile.objects.filter(public_user=True).select_related('user')
116 context = super(UserListView, self).get_context_data(**kwargs)
117 context.update({'title': "Dashboard Users", 'users': users})
121 def account_detail_view(request):
122 template = "account/details.html"
123 return render(request, template)
126 def account_resource_view(request):
128 Display a user's resources.
130 gathers a users genericResoureBundles and
131 turns them into displayable objects
133 if not request.user.is_authenticated:
134 return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
135 template = "account/resource_list.html"
137 active_bundles = [book.resource for book in Booking.objects.filter(
138 owner=request.user, end__gte=timezone.now(), resource__template__temporary=False)]
139 active_resources = [bundle.template.id for bundle in active_bundles]
140 resource_list = list(ResourceTemplate.objects.filter(owner=request.user, temporary=False))
143 "resources": resource_list,
144 "active_resources": active_resources,
145 "title": "My Resources"
147 return render(request, template, context=context)
150 def account_booking_view(request):
151 if not request.user.is_authenticated:
152 return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
153 template = "account/booking_list.html"
154 bookings = list(Booking.objects.filter(owner=request.user, end__gt=timezone.now()).order_by("-start"))
155 my_old_bookings = Booking.objects.filter(owner=request.user, end__lt=timezone.now()).order_by("-start")
156 collab_old_bookings = request.user.collaborators.filter(end__lt=timezone.now()).order_by("-start")
157 expired_bookings = list(my_old_bookings.union(collab_old_bookings))
158 collab_bookings = list(request.user.collaborators.filter(end__gt=timezone.now()).order_by("-start"))
160 "title": "My Bookings",
161 "bookings": bookings,
162 "collab_bookings": collab_bookings,
163 "expired_bookings": expired_bookings
165 return render(request, template, context=context)
168 def account_images_view(request):
169 if not request.user.is_authenticated:
170 return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
171 template = "account/image_list.html"
172 my_images = Image.objects.filter(owner=request.user)
173 public_images = Image.objects.filter(public=True)
175 for image in my_images:
177 used_images[image.id] = "true"
181 "public_images": public_images,
182 "used_images": used_images
184 return render(request, template, context=context)
187 def template_delete_view(request, resource_id=None):
188 if not request.user.is_authenticated:
189 return HttpResponse(status=403)
190 template = get_object_or_404(ResourceTemplate, pk=resource_id)
191 if not request.user.id == template.owner.id:
192 return HttpResponse(status=403)
193 if Booking.objects.filter(resource__template=template, end__gt=timezone.now()).exists():
194 return HttpResponse(status=403)
195 template.public = False
196 template.temporary = True
198 return HttpResponse(status=200)
201 def booking_cancel_view(request, booking_id=None):
202 if not request.user.is_authenticated:
203 return HttpResponse('no') # 403?
204 booking = get_object_or_404(Booking, pk=booking_id)
205 if not request.user.id == booking.owner.id:
206 return HttpResponse('no') # 403?
208 if booking.end < timezone.now(): # booking already over
209 return HttpResponse('')
211 booking.end = timezone.now()
213 return HttpResponse('')
216 def image_delete_view(request, image_id=None):
217 if not request.user.is_authenticated:
218 return HttpResponse('no') # 403?
219 image = get_object_or_404(Image, pk=image_id)
220 if image.public or image.owner.id != request.user.id:
221 return HttpResponse('no') # 403?
222 # check if used in booking
224 return HttpResponse('no') # 403?
226 return HttpResponse('')