Skip to content
Snippets Groups Projects
Commit 3ac692f5 authored by Sivert Kronen Hatteberg's avatar Sivert Kronen Hatteberg
Browse files

Merge branch 'GREG-312-speedup-frontpage' into 'master'

Frontpage speedup

See merge request !375
parents c59f1b7c 87c7ace2
No related branches found
No related tags found
1 merge request!375Frontpage speedup
Pipeline #178173 passed
......@@ -4,6 +4,7 @@ import { parseIdentity, parseRole, fetchJsonOpts } from 'utils'
const useGuests = () => {
const [guests, setGuests] = useState<Guest[]>([])
const [loading, setLoading] = useState<boolean>(true)
const getGuestsInfo = () =>
fetch('/api/ui/v1/guests/', fetchJsonOpts())
......@@ -28,8 +29,12 @@ const useGuests = () => {
})
)
)
setLoading(false)
})
.catch(() => {
setGuests([])
setLoading(false)
})
.catch(() => setGuests([]))
const reloadGuests = () => {
getGuestsInfo()
......@@ -39,7 +44,7 @@ const useGuests = () => {
getGuestsInfo()
}, [])
return { guests, reloadGuests }
return { guests, reloadGuests, loading }
}
export default useGuests
......@@ -17,6 +17,7 @@ import {
import { styled } from '@mui/system'
import { useState } from 'react'
import Loading from 'components/loading'
import Page from 'components/page'
import { differenceInDays, format, isBefore } from 'date-fns'
import { Guest, Role } from 'interfaces'
......@@ -47,6 +48,7 @@ interface GuestTableProps {
interface FrontPageProps {
guests: Guest[]
loading: boolean
}
const StyledTableRow = styled(TableRow)({
......@@ -401,15 +403,22 @@ const WaitingGuests = ({ persons }: GuestProps) => {
)
}
function FrontPage({ guests }: FrontPageProps) {
function FrontPage({ guests, loading }: FrontPageProps) {
return (
<Page pageWidth>
<SponsorGuestButtons yourGuestsActive />
<InvitedGuests persons={guests} />
<br />
<WaitingGuests persons={guests} />
<br />
<ActiveGuests persons={guests} />
{loading ? (
<Loading />
) : (
<>
<InvitedGuests persons={guests} />
<br />
<WaitingGuests persons={guests} />
<br />
<ActiveGuests persons={guests} />
</>
)}
</Page>
)
}
......
......@@ -5,7 +5,7 @@ import useGuests from 'hooks/useGuests'
import GuestRoutes from './guest'
function Sponsor() {
const { guests, reloadGuests } = useGuests()
const { guests, reloadGuests, loading } = useGuests()
return (
<Routes>
......@@ -13,7 +13,10 @@ function Sponsor() {
path="guest/:pid/*"
element={<GuestRoutes reloadGuests={reloadGuests} />}
/>
<Route path="" element={<FrontPage guests={guests} />} />
<Route
path=""
element={<FrontPage guests={guests} loading={loading} />}
/>
</Routes>
)
}
......
......@@ -709,7 +709,11 @@ class InvitationLink(BaseModel):
uuid = models.UUIDField(null=False, default=uuid.uuid4, blank=False)
invitation = models.ForeignKey(
"Invitation", on_delete=models.CASCADE, null=False, blank=False
"Invitation",
on_delete=models.CASCADE,
null=False,
blank=False,
related_name="invitation_links",
)
expire = models.DateTimeField(blank=False, null=False)
......@@ -727,7 +731,13 @@ class Invitation(BaseModel):
Deleting the InvitedPerson deletes the Invitation.
"""
role = models.ForeignKey("Role", null=False, blank=False, on_delete=models.CASCADE)
role = models.ForeignKey(
"Role",
null=False,
blank=False,
on_delete=models.CASCADE,
related_name="invitations",
)
def __str__(self) -> str:
return f"{self.__class__.__name__}(id={self.pk}, role={self.role})"
import datetime
from typing import Literal
from django.conf import settings
from django.utils import timezone
......@@ -288,3 +289,93 @@ class GuestSerializer(serializers.ModelSerializer):
"invitation_status",
"roles",
]
class FrontPageGuestSerializer(serializers.ModelSerializer):
"""
Serializer used for presenting guests to sponsors.
"""
pid = CharField(source="id", read_only=True)
first = CharField(source="first_name", read_only=True)
last = CharField(source="last_name", read_only=True)
active = SerializerMethodField(source="active", read_only=True)
registered = BooleanField(source="is_registered", read_only=True)
verified = SerializerMethodField(source="verified", read_only=True)
invitation_status = SerializerMethodField(
source="get_invitation_status", read_only=True
)
roles = ExtendedRoleSerializer(many=True, read_only=True)
def get_active(self, obj: Person) -> bool:
return obj.is_registered and self.get_verified(obj)
def get_verified(self, obj: Person) -> bool:
return (
len(
[
x
for x in obj.identities.all()
if x.type
in [
Identity.IdentityType.NORWEGIAN_NATIONAL_ID_NUMBER,
Identity.IdentityType.PASSPORT_NUMBER,
]
and x.verified_at
and x.verified_at <= timezone.now()
]
)
>= 1
)
def get_invitation_status(
self, obj: Person
) -> Literal["active", "expired", "invalidEmail", "none"]:
private_email = next(
iter(
[
x
for x in obj.identities.all()
if x.type == Identity.IdentityType.PRIVATE_EMAIL
]
),
None,
)
if private_email and private_email.invalid:
return "invalidEmail"
invitations = [
item
for sublist in [list(x.invitations.all()) for x in obj.roles.all()]
for item in sublist
]
# Get all invitation_links from all invitations and flatten them
invitation_links = [
item
for sublist in [list(x.invitation_links.all()) for x in invitations]
for item in sublist
]
non_expired_links = [x for x in invitation_links if x.expire > timezone.now()]
if len(non_expired_links) > 0:
return "active"
if len(invitation_links) > 0:
return "expired"
return "none"
class Meta:
model = Person
fields = [
"pid",
"first",
"last",
"active",
"registered",
"verified",
"invitation_status",
"roles",
]
from rest_framework import mixins
from rest_framework import status
from rest_framework import mixins, status
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
......@@ -11,6 +10,7 @@ from greg.utils import is_identity_duplicate
from gregui import validation
from gregui.api.serializers.guest import (
GuestSerializer,
FrontPageGuestSerializer,
create_identity_or_update,
)
from gregui.api.serializers.identity import IdentityDuplicateError
......@@ -121,7 +121,7 @@ class GuestInfoViewSet(mixins.ListModelMixin, GenericViewSet):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated, IsSponsor]
serializer_class = GuestSerializer
serializer_class = FrontPageGuestSerializer
def get_queryset(self):
"""
......@@ -135,6 +135,16 @@ class GuestInfoViewSet(mixins.ListModelMixin, GenericViewSet):
units = user.sponsor.get_allowed_units()
return (
Person.objects.filter(roles__orgunit__in=list(units))
.prefetch_related(
"identities",
"roles",
"roles__sponsor",
"roles__orgunit",
"roles__person",
"roles__type",
"roles__invitations",
"roles__invitations__invitation_links",
)
.distinct()
.order_by("id")
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment