def BetaSendInvite(request, pk=None, template_name="backend/beta_send_invite.html"): invite = get_object_or_404(InviteRequest, pk=pk) if invite.invited: return HttpResponseRedirect(reverse_lazy('beta_invites')) try: user = User.objects.get(email=invite.email) except User.DoesNotExist: user = None if request.POST: password = None if user is None: password = uuid.uuid1() user = User.objects.create_user( invite.email, invite.email, password) user.is_active = True user.save() subject = 'REDMAP Beta Invite' from_email = settings.DEFAULT_FROM_EMAIL to = invite.email dictionary = { 'email': invite.email, 'password': password, 'domain': Site.objects.get_current().domain, } text_content = render_to_string( 'backend/email/text/beta_invite.html', dictionary) html_content = render_to_string( 'backend/email/html/beta_invite.html', dictionary) msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) msg.attach_alternative(html_content, "text/html") msg.send() invite.invited = True invite.save() return HttpResponseRedirect(reverse_lazy('beta_invites')) return render( request, template_name, { 'invite': invite, 'user': user, } )
def BetaSendInvite(request, pk=None, template_name="backend/beta_send_invite.html"): invite = get_object_or_404(InviteRequest, pk=pk) if invite.invited: return HttpResponseRedirect(reverse_lazy('beta_invites')) try: user = User.objects.get(email=invite.email) except User.DoesNotExist: user = None if request.POST: password = None if user is None: password = uuid.uuid1() user = User.objects.create_user(invite.email, invite.email, password) user.is_active = True user.save() subject = 'REDMAP Beta Invite' from_email = settings.DEFAULT_FROM_EMAIL to = invite.email dictionary = { 'email': invite.email, 'password': password, 'domain': Site.objects.get_current().domain, } text_content = render_to_string('backend/email/text/beta_invite.html', dictionary) html_content = render_to_string('backend/email/html/beta_invite.html', dictionary) msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) msg.attach_alternative(html_content, "text/html") msg.send() invite.invited = True invite.save() return HttpResponseRedirect(reverse_lazy('beta_invites')) return render(request, template_name, { 'invite': invite, 'user': user, })
def SightingReassign(request, pk=None, template_name="backend/sighting_reassign.html"): if pk: sighting = get_object_or_404(Sighting, pk=pk) if request.method == 'POST': data = request.POST user = User.objects.get(pk=data.get('username')) comment = data.get('comment') sighting.reassign(request.user, user, comment) return HttpResponseRedirect(reverse_lazy('sightings_unvalidated')) else: form = SightingReassignForm() return render( request, template_name, { 'form': form, 'sighting': sighting } )
def GroupEdit(request, pk=None, template_name='frontend/group_edit.html'): if pk: group = FBGroup.objects.get(pk=pk) else: group = FBGroup() if request.POST: form = FBGroupForm(request.POST, request.FILES, instance=group) if form.is_valid(): form.save() if not pk: group.owner = request.user group.save() membership = PersonInGroup() membership.group = group membership.person = request.user membership.save() return HttpResponseRedirect(reverse_lazy('my_groups')) else: form = FBGroupForm(instance=group) context = {'form': form, 'group': group, 'pk': pk} return render(request, template_name, context)
def GroupView(request, pk=None, template_name='frontend/group_view.html'): group = get_object_or_404(FBGroup, pk=pk) action = request.POST.get('action') if action: if request.user.is_authenticated(): if action == 'join': membership = PersonInGroup() membership.group = group membership.person = request.user membership.save() elif action == 'leave': membership =\ PersonInGroup.objects.filter(group=group, person=request.user) membership.delete() elif action == 'delete': print 'Delete is unimplemented!' # TODO ? else: messages.error(request, 'You must log in to join a group') return HttpResponseRedirect(reverse_lazy('auth_login')) members = PersonInGroup.objects.filter(group=group) ids = [] for member in members: ids.append(member.person.id) sightings = Sighting.objects.get_public().filter(user__id__in=ids) if request.user.is_authenticated(): is_member = PersonInGroup.objects.filter(group=group, person=request.user).exists() is_owner = group.owner == request.user else: is_member = False is_owner = False return render( request, template_name, { 'pk': pk, 'group': group, 'members': members, 'count': len(members), 'sightings': sightings, 'is_member': is_member, 'is_owner': is_owner, })
def OrganisationDelete(request, pk=None, template_name="backend/organisation_delete.html"): organisation = Organisation.objects.get(pk=pk) if pk and request.POST: organisation.delete() return HttpResponseRedirect(reverse_lazy('organisation_index')) return render(request, template_name, {'organisation': organisation})
def SightingDelete(request, pk=None, template_name="backend/sighting_delete.html"): sighting = Sighting.objects.get(pk=pk) if pk and request.POST: sighting.delete() return HttpResponseRedirect(reverse_lazy('sightings_list')) return render(request, template_name, {'sighting': sighting})
def DeleteEmailTemplate(request, pk=None, template_name="backend/delete_email_template.html"): rule = ValidationMessageTemplate.objects.get(pk=pk) if pk and request.POST: rule.delete() return HttpResponseRedirect(reverse_lazy('manage_email_templates')) return render(request, template_name, {'rule': rule})
def DeleteSpeciesExpert(request, pk=None, template_name="backend/delete_expert.html"): allocation = SpeciesAllocation.objects.get(pk=pk) if pk and request.POST: allocation.delete() return HttpResponseRedirect(reverse_lazy('manage_experts')) return render(request, template_name, {'allocation': allocation})
def MemberDelete(request, pk=None, template_name="backend/member_delete.html"): member = User.objects.get(pk=pk) if pk and request.POST: member.is_active = False member.save() return HttpResponseRedirect(reverse_lazy('member_index')) return render(request, template_name, {'member': member})
def delete_validation_rule(request, pk, template_name="backend/delete_validation_rule.html" ): rule = get_object_or_404(SightingValidationRule, pk=pk) if request.POST: rule.delete() return HttpResponseRedirect(reverse_lazy('validation_rules')) return render(request, template_name, {'rule': rule})
def ValidationConditionDelete( request, pk=None, template_name="backend/validation_condition_delete.html"): condition = SightingValidationCondition.objects.get(pk=pk) if pk and request.POST: condition.delete() return HttpResponseRedirect(reverse_lazy('validation_conditions')) return render(request, template_name, {'condition': condition})
def AdministratorAllocationDelete( request, pk=None, template_name="backend/administrator_allocation_delete.html"): allocation = AdministratorAllocation.objects.get(pk=pk) if pk and request.POST: allocation.delete() return HttpResponseRedirect(reverse_lazy('administrator_allocations')) return render(request, template_name, {'allocation': allocation})
def delete_validation_rule(request, pk, template_name="backend/delete_validation_rule.html"): rule = get_object_or_404(SightingValidationRule, pk=pk) if request.POST: rule.delete() return HttpResponseRedirect(reverse_lazy('validation_rules')) return render( request, template_name, {'rule': rule} )
def FaqDelete(request, pk=None, template_name="backend/faq_delete.html"): faq = Faq.objects.get(pk=pk) if pk and request.POST: faq.delete() return HttpResponseRedirect(reverse_lazy('faq_index')) return render( request, template_name, {'faq': faq} )
def SponsorCategoryDelete(request, pk=None, template_name="backend/sponsor_category_delete.html"): category = SponsorCategory.objects.get(pk=pk) if pk and request.POST: category.delete() return HttpResponseRedirect(reverse_lazy('sponsor_category_index')) return render( request, template_name, {'category': category} )
def SightingSpam(request, pk=None, template_name="backend/sighting_spam.html"): sighting = get_object_or_404(Sighting, pk=pk) if request.POST: sighting.report_spam(request.POST.get('comment')) return HttpResponseRedirect(reverse_lazy('sightings_unvalidated')) return render(request, template_name, { 'sighting': sighting, 'pk': pk, 'form': SightingSpamForm() })
def SightingSpam(request, pk=None, template_name="backend/sighting_spam.html"): sighting = get_object_or_404(Sighting, pk=pk) if request.POST: sighting.report_spam(request.POST.get('comment')) return HttpResponseRedirect(reverse_lazy('sightings_unvalidated')) return render( request, template_name, {'sighting': sighting, 'pk': pk, 'form': SightingSpamForm()} )
def SponsorDelete(request, pk=None, template_name="backend/sponsor_delete.html"): sponsor = Sponsor.objects.get(pk=pk) if pk and request.POST: sponsor.delete() return HttpResponseRedirect(reverse_lazy('sponsor_index')) return render( request, template_name, {'sponsor': sponsor} )
def RegionalAdministratorDelete( request, pk=None, template_name="backend/regional_administrator_delete.html"): user = User.objects.get(pk=pk) if pk and request.POST: group = Group.objects.get(name="Regional Administrators") group.user_set.remove(user) return HttpResponseRedirect(reverse_lazy('regional_administrators')) return render(request, template_name, {'user': user})
def SightingDelete(request, pk=None, template_name="backend/sighting_delete.html"): sighting = Sighting.objects.get(pk=pk) if pk and request.POST: sighting.delete() return HttpResponseRedirect(reverse_lazy('sightings_list')) return render( request, template_name, {'sighting': sighting} )
def OrganisationDelete(request, pk=None, template_name="backend/organisation_delete.html"): organisation = Organisation.objects.get(pk=pk) if pk and request.POST: organisation.delete() return HttpResponseRedirect(reverse_lazy('organisation_index')) return render( request, template_name, {'organisation': organisation} )
def DeleteSpeciesExpert(request, pk=None, template_name="backend/delete_expert.html"): allocation = SpeciesAllocation.objects.get(pk=pk) if pk and request.POST: allocation.delete() return HttpResponseRedirect(reverse_lazy('manage_experts')) return render( request, template_name, {'allocation': allocation} )
def DeleteScientist(request, pk=None, template_name="backend/delete_scientist.html"): user = User.objects.get(pk=pk) if pk and request.POST: group = Group.objects.get(name="Scientists") group.user_set.remove(user) return HttpResponseRedirect(reverse_lazy('scientist_index')) return render(request, template_name, {'user': user})
def ValidationConditionDelete( request, pk=None, template_name="backend/validation_condition_delete.html"): condition = SightingValidationCondition.objects.get(pk=pk) if pk and request.POST: condition.delete() return HttpResponseRedirect(reverse_lazy('validation_conditions')) return render( request, template_name, {'condition': condition} )
def page_delete(request, book_id, pk): book = get_object_or_404(Page, pk=book_id) page = get_object_or_404(Page, pk=pk) if pk and request.POST: page.delete() return HttpResponseRedirect(reverse_lazy('cms_index')) return render( request, "cms/page_delete.html", {'page': page, 'book': book} )
def DeleteEmailTemplate(request, pk=None, template_name="backend/delete_email_template.html"): rule = ValidationMessageTemplate.objects.get(pk=pk) if pk and request.POST: rule.delete() return HttpResponseRedirect(reverse_lazy('manage_email_templates')) return render( request, template_name, {'rule': rule} )
def AdministratorAllocationDelete(request, pk=None, template_name="backend/administrator_allocation_delete.html"): allocation = AdministratorAllocation.objects.get(pk=pk) if pk and request.POST: allocation.delete() return HttpResponseRedirect(reverse_lazy('administrator_allocations')) return render( request, template_name, {'allocation': allocation} )
def RegionalAdministratorDelete(request, pk=None, template_name="backend/regional_administrator_delete.html"): user = User.objects.get(pk=pk) if pk and request.POST: group = Group.objects.get(name="Regional Administrators") group.user_set.remove(user) return HttpResponseRedirect(reverse_lazy('regional_administrators')) return render( request, template_name, {'user': user} )
def GroupDelete(request, pk=None, template_name='frontend/group_delete.html'): group = get_object_or_404(FBGroup, pk=pk) members = PersonInGroup.objects.filter(group=group) if request.POST: group.delete() return HttpResponseRedirect(reverse_lazy('my_groups')) return render(request, template_name, { 'pk': pk, 'group': group, 'members': members, 'count': len(members), })
def MemberDelete(request, pk=None, template_name="backend/member_delete.html"): member = User.objects.get(pk=pk) if pk and request.POST: member.is_active = False member.save() return HttpResponseRedirect(reverse_lazy('member_index')) return render( request, template_name, {'member': member} )
def DeleteScientist(request, pk=None, template_name="backend/delete_scientist.html"): user = User.objects.get(pk=pk) if pk and request.POST: group = Group.objects.get(name="Scientists") group.user_set.remove(user) return HttpResponseRedirect(reverse_lazy('scientist_index')) return render( request, template_name, {'user': user} )
def MemberAdd(request, pk=None, template_name="backend/member_add.html"): if pk: member = get_object_or_404(User, pk=pk) else: member = User() if request.POST: form = UserAddForm(request.POST, instance=member) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('member_index')) else: form = UserAddForm(instance=member) return render(request, template_name, {'form': form, 'pk': pk})
def AddSpeciesExpert(request, pk=None, template_name="backend/add_expert.html"): if pk: allocation = get_object_or_404(SpeciesAllocation, pk=pk) else: allocation = SpeciesAllocation() if request.POST: form = AddSpeciesAllocation(request.POST, instance=allocation) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('manage_experts')) else: form = AddSpeciesAllocation(instance=allocation) return render(request, template_name, {'form': form, 'pk': pk})
def AddEmailTemplate(request, pk=None, template_name="backend/add_email_template.html"): if pk: rule = get_object_or_404(ValidationMessageTemplate, pk=pk) else: rule = ValidationMessageTemplate() if request.POST: form = AddEmailTemplateForm(request.POST, instance=rule) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('manage_email_templates')) else: form = AddEmailTemplateForm(instance=rule) return render(request, template_name, {'form': form, 'pk': pk})
def ValidationConditionAdd( request, pk=None, template_name="backend/validation_condition_edit.html"): if pk: condition = get_object_or_404(SightingValidationCondition, pk=pk) else: condition = SightingValidationCondition() if request.POST: form = ValidationConditionForm(request.POST, instance=condition) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('validation_conditions')) else: form = ValidationConditionForm(instance=condition) return render(request, template_name, {'form': form, 'pk': pk})
def SightingEdit(request, pk=None, template_name="backend/sighting_edit.html"): if pk: sighting = get_object_or_404(Sighting, pk=pk) else: sighting = Sighting() if request.POST: form = EditSightingForm(request.POST, instance=sighting) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('sightings_list')) else: sighting.sighting_date = sighting.sighting_date.strftime('%Y-%m-%d') form = EditSightingForm(instance=sighting) accuracies = Accuracy.objects.all() accuracy_dict = {} for a in accuracies: try: a.code = int(a.code) except: a.code = a.code[0:-1] accuracy_dict.update({a.id: a.code}) trackings = sighting.sighting_tracking.all() for tracking in trackings: tracking.validation_response = ValidationResponse.objects.filter( sighting_tracking=tracking) return render( request, template_name, { 'form': form, 'pk': pk, 'accuracies': accuracy_dict, 'sighting': sighting, 'sighting_tracking': trackings, } )
def SightingEdit(request, pk=None, template_name="backend/sighting_edit.html"): if pk: sighting = get_object_or_404(Sighting, pk=pk) else: sighting = Sighting() if request.POST: form = EditSightingForm(request.POST, instance=sighting) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('sightings_list')) else: sighting.sighting_date = sighting.sighting_date.strftime('%Y-%m-%d') form = EditSightingForm(instance=sighting) accuracies = Accuracy.objects.all() accuracy_dict = {} for a in accuracies: try: a.code = int(a.code) except: # FIXME: This is a bad assumption (ie. that slicing off the last # character will fix this type issue) # See Ticket #1609 a.code = a.code[0:-1] accuracy_dict.update({a.id: a.code}) trackings = sighting.sighting_tracking.all() for tracking in trackings: tracking.validation_response = ValidationResponse.objects.filter( sighting_tracking=tracking) return render( request, template_name, { 'form': form, 'pk': pk, 'accuracies': accuracy_dict, 'sighting': sighting, 'sighting_tracking': trackings, })
def AddSpeciesExpert(request, pk=None, template_name="backend/add_expert.html"): if pk: allocation = get_object_or_404(SpeciesAllocation, pk=pk) else: allocation = SpeciesAllocation() if request.POST: form = AddSpeciesAllocation(request.POST, instance=allocation) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('manage_experts')) else: form = AddSpeciesAllocation(instance=allocation) return render( request, template_name, {'form': form, 'pk': pk} )
def AdministratorAllocationEdit( request, pk=None, template_name="backend/administrator_allocation_edit.html"): if pk: allocation = get_object_or_404(AdministratorAllocation, pk=pk) else: allocation = AdministratorAllocation() if request.POST: form = AdministratorAllocationForm(request.POST, instance=allocation) if form.is_valid(): form.save() return HttpResponseRedirect( reverse_lazy('administrator_allocations')) else: form = AdministratorAllocationForm(instance=allocation) return render(request, template_name, {'form': form, 'pk': pk})
def AdministratorAllocationEdit(request, pk=None, template_name="backend/administrator_allocation_edit.html"): if pk: allocation = get_object_or_404(AdministratorAllocation, pk=pk) else: allocation = AdministratorAllocation() if request.POST: form = AdministratorAllocationForm(request.POST, instance=allocation) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('administrator_allocations')) else: form = AdministratorAllocationForm(instance=allocation) return render( request, template_name, {'form': form, 'pk': pk} )
def SponsorCategoryEdit(request, pk=None, template_name="backend/sponsor_category_edit.html"): if pk: category = get_object_or_404(SponsorCategory, pk=pk) else: category = SponsorCategory() if request.POST: form = AddSponsorCategoryForm(request.POST, request.FILES, instance=category) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('sponsor_category_index')) else: form = AddSponsorCategoryForm(instance=category) return render( request, template_name, {'form': form, 'pk': pk} )
def SightingReassign(request, pk=None, template_name="backend/sighting_reassign.html"): if pk: sighting = get_object_or_404(Sighting, pk=pk) if request.method == 'POST': data = request.POST user = User.objects.get(pk=data.get('username')) comment = data.get('comment') sighting.reassign(request.user, user, comment) return HttpResponseRedirect(reverse_lazy('sightings_unvalidated')) else: form = SightingReassignForm() return render(request, template_name, {'form': form, 'sighting': sighting})
def FaqEdit(request, pk=None, template_name="backend/faq_edit.html"): if pk: faq = get_object_or_404(Faq, pk=pk) else: faq = Faq() if request.POST: form = AddFaqForm(request.POST, request.FILES, instance=faq) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('faq_index')) else: form = AddFaqForm(instance=faq) return render( request, template_name, {'form': form, 'pk': pk} )
def SponsorAdd(request, pk=None, template_name="backend/sponsor_add.html"): if pk: sponsor = get_object_or_404(Sponsor, pk=pk) else: sponsor = Sponsor() if request.POST: form = AddSponsorForm(request.POST, request.FILES, instance=sponsor) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('sponsor_index')) else: form = AddSponsorForm(instance=sponsor) return render( request, template_name, {'form': form, 'pk': pk} )
def OrganisationAdd(request, pk=None, template_name="backend/organisation_add.html"): if pk: organisation = get_object_or_404(Organisation, pk=pk) else: organisation = Organisation() if request.POST: form = OrganisationAddForm(request.POST, request.FILES, instance=organisation) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('organisation_index')) else: form = OrganisationAddForm(instance=organisation) return render(request, template_name, {'form': form, 'pk': pk})
def ValidationConditionAdd( request, pk=None, template_name="backend/validation_condition_edit.html"): if pk: condition = get_object_or_404(SightingValidationCondition, pk=pk) else: condition = SightingValidationCondition() if request.POST: form = ValidationConditionForm(request.POST, instance=condition) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('validation_conditions')) else: form = ValidationConditionForm(instance=condition) return render( request, template_name, {'form': form, 'pk': pk} )
def AddEmailTemplate(request, pk=None, template_name="backend/add_email_template.html"): if pk: rule = get_object_or_404(ValidationMessageTemplate, pk=pk) else: rule = ValidationMessageTemplate() if request.POST: form = AddEmailTemplateForm(request.POST, instance=rule) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('manage_email_templates')) else: form = AddEmailTemplateForm(instance=rule) return render( request, template_name, {'form': form, 'pk': pk} )
def MemberAdd(request, pk=None, template_name="backend/member_add.html"): if pk: member = get_object_or_404(User, pk=pk) else: member = User() if request.POST: form = UserAddForm(request.POST, instance=member) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('member_index')) else: form = UserAddForm(instance=member) return render( request, template_name, {'form': form, 'pk': pk} )
def OrganisationAdd(request, pk=None, template_name="backend/organisation_add.html"): if pk: organisation = get_object_or_404(Organisation, pk=pk) else: organisation = Organisation() if request.POST: form = OrganisationAddForm( request.POST, request.FILES, instance=organisation) if form.is_valid(): form.save() return HttpResponseRedirect(reverse_lazy('organisation_index')) else: form = OrganisationAddForm(instance=organisation) return render( request, template_name, {'form': form, 'pk': pk} )
def done(self, form_list, *args, **kwargs): """ Process and save validation report """ context = self.get_context_data(form=form_list) result = is_sighting_valid(self) sighting = context['sighting'] for form in form_list: for field, value in form.cleaned_data.iteritems(): setattr(sighting, field, value) sighting.save() if sighting.tracker is None: """ This sighting has no active tracker, which probably means that it has already been verified in the past. We should create a new tracker for the current user. """ sighting.assign(self.request.user, "Re-validating sighting") if not sighting.tracker.person == self.request.user: sighting.reassign(sighting, self.request.user, 'Reassigned\ to %s' % self.request.user.profile) responses = self.get_responses() ValidationResponse.objects.record_responses(sighting, responses) is_valid = result.get('valid') if is_valid: if result.get('photo'): sighting.report_valid_with_photo( ValidationResponse.objects .get_photo_matches_species_response(sighting), sighting.assessment, sighting.is_displayed_on_site, sighting.is_published) else: sighting.report_valid_without_photo( sighting.assessment, sighting.is_displayed_on_site, sighting.is_published) else: sighting.report_invalid(sighting.assessment, sighting.is_published) if is_valid: subject = "#%s - Valid sighting" % sighting.pk else: subject = "#%s - Invalid sighting" % sighting.pk from_email = sighting.region.email to = sighting.user.email REPLACEMENTS = dict([ ('{sighter}', sighting.user.username), ('{species}', sighting.species_name), ('{sighting_url}', reverse('sighting_detail', kwargs={'pk': sighting.pk})), ]) def replacer(m): return REPLACEMENTS[m.group(0)] content = sighting.message r = re.compile('|'.join(REPLACEMENTS.keys())) content = r.sub(replacer, content) text_content = content html_content = "<pre>" + content + "</pre>" msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) msg.attach_alternative(html_content, "text/html") msg.send() transaction.commit() if is_valid and sighting.user.get_profile().has_facebook_account(): sighting.post_to_facebook(request=self.request) return HttpResponseRedirect(reverse_lazy('dashboard'))
from redmap.apps.backend import emails from redmap.common.tags import get_redmap_tag from redmap.common.util import reverse_lazy from redmapdb.models import Sighting, SpeciesAllocation, SightingTracking, \ Accuracy, Region, Organisation, Species, AdministratorAllocation from registration.models import RegistrationProfile from tagging.models import Tag, TaggedItem from zinnia.models import Entry import json import operator import re import uuid from cms.models import CopyBlock login_url = reverse_lazy('auth_login') def is_sighting_valid(wizard): conditions = wizard.get_cleaned_data_for_step('0').get('conditions') sighting = wizard.instance_dict['0'] # TODO: better as an arg really has_photo = bool(sighting.photo_url) rule = SightingValidationRule.objects.find_matching_rule( conditions, has_photo) if rule is not None: assessment = rule.validation_message_template.public_assessment