2020-02-24 22:28:52 +00:00
import base64
import io
import logging
import qrcode
from django . contrib . gis . db . models import PointField
from django . core . exceptions import ValidationError
from django . db import models
from django . shortcuts import reverse
from django . utils . text import slugify
2020-03-28 10:45:54 +00:00
from maps . utils import LeafletMarkerChoices
2020-02-24 22:28:52 +00:00
from utils . models import CampRelatedModel , UUIDModel
logger = logging . getLogger ( " bornhack. %s " % __name__ )
class FacilityQuickFeedback ( models . Model ) :
"""
This model contains the various options for giving quick feedback which we present to the user
when giving feedback on facilities . Think " Needs cleaning " or " Doesn ' t work " and such .
This model is not Camp specific .
"""
feedback = models . CharField ( max_length = 100 )
icon = models . CharField (
max_length = 100 ,
default = " fas fa-exclamation " ,
blank = True ,
help_text = " Name of the fontawesome icon to use, including the ' fab fa- ' or ' fas fa- ' part. Defaults to an exclamation mark icon. " ,
)
def __str__ ( self ) :
return self . feedback
class FacilityType ( CampRelatedModel ) :
"""
Facility types are used to group similar facilities , like Toilets , Showers , Thrashcans . . .
facilities . Type has a m2m relationship with FeedbackChoice which determines which choices
are presented for giving feedback for this Facility
"""
class Meta :
unique_together = [ ( " slug " , " responsible_team " ) ]
name = models . CharField ( max_length = 100 , help_text = " The name of this facility type " )
slug = models . SlugField (
blank = True ,
help_text = " The url slug for this facility type. Leave blank to autogenerate one. " ,
)
description = models . TextField ( help_text = " Description of this facility type " )
icon = models . CharField (
max_length = 100 ,
default = " fas fa-list " ,
blank = True ,
help_text = " Name of the fontawesome icon to use, including the ' fab fa- ' or ' fas fa- ' part. " ,
)
2020-03-28 10:45:54 +00:00
marker = models . CharField (
max_length = 10 ,
choices = LeafletMarkerChoices . choices ,
default = LeafletMarkerChoices . BLUE ,
help_text = " The name/colour of the Leaflet marker to use for this facility type. " ,
)
2020-02-24 22:28:52 +00:00
responsible_team = models . ForeignKey (
" teams.Team " ,
on_delete = models . PROTECT ,
help_text = " The Team responsible for this type of facility. This team will get the notification when we get a new FacilityFeedback for a Facility of this type. " ,
)
quickfeedback_options = models . ManyToManyField (
to = " facilities.FacilityQuickFeedback " ,
help_text = " Pick the quick feedback options the user should be presented with when submitting Feedback for a Facility of this type. Pick at least the ' N/A ' option if none of the other applies. " ,
)
@property
def camp ( self ) :
return self . responsible_team . camp
camp_filter = " responsible_team__camp "
def __str__ ( self ) :
return f " { self . name } ( { self . camp } ) "
def save ( self , * * kwargs ) :
if not self . slug :
self . slug = slugify ( self . name )
if not self . slug :
raise ValidationError ( " Unable to slugify " )
super ( ) . save ( * * kwargs )
class Facility ( CampRelatedModel , UUIDModel ) :
"""
Facilities are toilets , thrashcans , cooking and dishwashing areas , and any other part of the event which could need attention or maintenance .
"""
facility_type = models . ForeignKey (
" facilities.FacilityType " , related_name = " facilities " , on_delete = models . PROTECT
)
name = models . CharField (
max_length = 100 , help_text = " Name or description of this facility " ,
)
description = models . TextField ( help_text = " Description of this facility " )
location = PointField ( help_text = " The location of this facility " )
@property
def team ( self ) :
return self . facility_type . responsible_team
@property
def camp ( self ) :
return self . facility_type . camp
camp_filter = " facility_type__responsible_team__camp "
def __str__ ( self ) :
return self . name
def get_feedback_url ( self , request ) :
return request . build_absolute_uri (
reverse (
" facilities:facility_feedback " ,
kwargs = {
" camp_slug " : self . facility_type . responsible_team . camp . slug ,
" facility_type_slug " : self . facility_type . slug ,
" facility_uuid " : self . uuid ,
} ,
)
)
def get_feedback_qr ( self , request ) :
qr = qrcode . make (
self . get_feedback_url ( request ) ,
version = 1 ,
error_correction = qrcode . constants . ERROR_CORRECT_H ,
) . resize ( ( 250 , 250 ) )
file_like = io . BytesIO ( )
qr . save ( file_like , format = " png " )
qrcode_base64 = base64 . b64encode ( file_like . getvalue ( ) ) . decode ( " utf-8 " )
return f " data:image/png;base64, { qrcode_base64 } "
class FacilityFeedback ( CampRelatedModel ) :
"""
This model contains participant feedback for Facilities .
It is linked to the user and the facility , and to the
quick_feedback choice the user picked ( if any ) .
"""
user = models . ForeignKey (
" auth.User " ,
null = True ,
blank = True ,
on_delete = models . PROTECT ,
related_name = " facility_feebacks " ,
help_text = " The User this feedback came from, empty if the user submits anonymously " ,
)
facility = models . ForeignKey (
" facilities.Facility " ,
related_name = " feedbacks " ,
on_delete = models . PROTECT ,
help_text = " The Facility this feeback is about " ,
)
quick_feedback = models . ForeignKey (
" facilities.FacilityQuickFeedback " ,
on_delete = models . PROTECT ,
related_name = " feedbacks " ,
help_text = " Quick feedback options. Elaborate in comment field as needed. " ,
)
comment = models . TextField (
blank = True , help_text = " Any comments or feedback about this facility? (optional) "
)
urgent = models . BooleanField (
default = False ,
help_text = " Check if this is an urgent issue. Will trigger immediate notifications to the responsible team. " ,
)
handled = models . BooleanField (
default = False ,
help_text = " True if this feedback has been handled by the responsible team, False if not " ,
)
handled_by = models . ForeignKey (
" auth.User " ,
null = True ,
blank = True ,
on_delete = models . PROTECT ,
related_name = " facility_feebacks_handled " ,
help_text = " The User who handled this feedback " ,
)
@property
def camp ( self ) :
return self . facility . camp
camp_filter = " facility__facility_type__responsible_team__camp "