# Path: lametro/models.py
# class LAMetroBill(Bill, SourcesMixin):
#     objects = LAMetroBillManager()
# 
#     class Meta:
#         proxy = True
# 
#     # LA METRO CUSTOMIZATION
#     @property
#     def friendly_name(self):
#         full_text = self.extras.get('plain_text')
# 
#         results = None
# 
#         if full_text:
#             results = format_full_text(full_text)
# 
#         if results:
#             title = parse_subject(results)
#         else:
#             title = self.bill_type
# 
#         return '{0} - {1}'.format(self.identifier, title.upper())
# 
#     # LA METRO CUSTOMIZATION
#     @property
#     def inferred_status(self):
#         # Get most recent action.
#         action = self.actions.last()
# 
#         # Get description of that action.
#         if action:
#             description = action.description
#         else:
#             description = ''
# 
#         return self._status(description)
# 
#     def _status(self, description):
#         if description and description.upper() in BILL_STATUS_DESCRIPTIONS.keys():
#             return BILL_STATUS_DESCRIPTIONS[description.upper()]['search_term']
#         return None
# 
#     # LA METRO CUSTOMIZATION
#     @property
#     def attachments(self):
#         return self.documents.all()
# 
#     @property
#     def controlling_body(self):
#         return self.from_organization
# 
#     @property
#     def topics(self):
#         return sorted(self.subject)
# 
#     @property
#     def rich_topics(self):
#         return LAMetroSubject.objects.filter(name__in=self.subject).order_by('name')
# 
#     @property
#     def board_report(self):
# 
#         try:
#             br = self.versions.get(note="Board Report")
#             br.url = br.links.get().url
#         except BillVersion.DoesNotExist:
#             br = None
# 
#         return br
# 
#     @property
#     def actions_and_agendas(self):
#         '''
#         Return list of dictionaries, each representing an action or an agenda on
#         which the given bill appears, in the format:
# 
#         {
#             'date': <datetime>,
#             'description': <str>,
#             'event': <LAMetroEvent>,
#             'organization': <Organization>
#         }
#         '''
#         actions = self.actions.all()
#         events = LAMetroEvent.objects.filter(agenda__related_entities__bill=self)
# 
#         data = []
# 
#         for action in actions:
#             try:
#                 event = LAMetroEvent.objects.get(\
#                     participants__entity_type='organization',\
#                     participants__organization=action.organization,
#                     start_time__date=action.date)
#             except LAMetroEvent.DoesNotExist:
#                 logger.warning(
#                     'Could not find event corresponding to action on Board ' +
#                     'Report {0} by {1} on {2}'.format(self.identifier, action.organization, action.date)
#                 )
#                 continue
# 
#             action_dict = {
#                 'date': action.date_dt,
#                 'description': action.description,
#                 'event': event,
#                 'organization': action.organization
#             }
# 
#             data.append(action_dict)
# 
#         for event in events:
#             try:
#                 # Attempt to return Metro org object.
#                 org = LAMetroOrganization.objects.get(
#                     id=event.participants.first().organization_id
#                 )
#             except LAMetroOrganization.DoesNotExist:
#                 # If a corresponding org does not exist, e.g., in the case of
#                 # appearing on the agenda of a public hearing, return the event
#                 # participant object.
#                 org = event.participants.first()
# 
#             event_dict = {
#                 'date': event.start_time.date(),
#                 'description': 'SCHEDULED',  # Use a description of "SCHEDULED"
#                 'event': event,
#                 'organization': org
#             }
# 
#             data.append(event_dict)
# 
#         # Sort actions by date, and list SCHEDULED actions before other actions on that date
#         # SCHEDULED descriptions are kept uppercase to use ascii-betical sorting
#         sorted_data = sorted(data, key=lambda x:(x['date'],\
#             x['description'].upper() if x['description'] == 'SCHEDULED' else x['description'].lower()))
# 
#         return sorted_data


import requests
from django import forms
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db.models import Q
from captcha.fields import ReCaptchaField
from captcha.fields import ReCaptchaV3
from haystack.backends import SQ
from haystack.inputs import Raw
from haystack.query import EmptySearchQuerySet
from councilmatic_core.views import CouncilmaticSearchForm
from lametro.models import LAMetroBill
            return EmptySearchQuerySet()

        sqs = super(LAMetroCouncilmaticSearchForm, self).search()

        has_query = hasattr(self, 'cleaned_data') and self.cleaned_data['q']

        if has_query:
            sqs = self._full_text_search(sqs)
            sqs = self._topic_search(sqs)

        return sqs


class AgendaUrlForm(forms.Form):

    agenda = forms.CharField(
        label='Agenda URL',
        max_length=500,
        error_messages={ 'required': 'Whoops! Please provide a valid URL.' },
        widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Enter URL...', 'id': 'agenda_url'}),
        )

    def clean_agenda(self):
        agenda_url = self.cleaned_data['agenda']

        try:
          r = requests.head(agenda_url)
          if r.status_code == 200:
              return agenda_url
          elif r.status_code == 404:

# Path: lametro/models.py
# class LAMetroBill(Bill, SourcesMixin):
#     objects = LAMetroBillManager()
# 
#     class Meta:
#         proxy = True
# 
#     # LA METRO CUSTOMIZATION
#     @property
#     def friendly_name(self):
#         full_text = self.extras.get('plain_text')
# 
#         results = None
# 
#         if full_text:
#             results = format_full_text(full_text)
# 
#         if results:
#             title = parse_subject(results)
#         else:
#             title = self.bill_type
# 
#         return '{0} - {1}'.format(self.identifier, title.upper())
# 
#     # LA METRO CUSTOMIZATION
#     @property
#     def inferred_status(self):
#         # Get most recent action.
#         action = self.actions.last()
# 
#         # Get description of that action.
#         if action:
#             description = action.description
#         else:
#             description = ''
# 
#         return self._status(description)
# 
#     def _status(self, description):
#         if description and description.upper() in BILL_STATUS_DESCRIPTIONS.keys():
#             return BILL_STATUS_DESCRIPTIONS[description.upper()]['search_term']
#         return None
# 
#     # LA METRO CUSTOMIZATION
#     @property
#     def attachments(self):
#         return self.documents.all()
# 
#     @property
#     def controlling_body(self):
#         return self.from_organization
# 
#     @property
#     def topics(self):
#         return sorted(self.subject)
# 
#     @property
#     def rich_topics(self):
#         return LAMetroSubject.objects.filter(name__in=self.subject).order_by('name')
# 
#     @property
#     def board_report(self):
# 
#         try:
#             br = self.versions.get(note="Board Report")
#             br.url = br.links.get().url
#         except BillVersion.DoesNotExist:
#             br = None
# 
#         return br
# 
#     @property
#     def actions_and_agendas(self):
#         '''
#         Return list of dictionaries, each representing an action or an agenda on
#         which the given bill appears, in the format:
# 
#         {
#             'date': <datetime>,
#             'description': <str>,
#             'event': <LAMetroEvent>,
#             'organization': <Organization>
#         }
#         '''
#         actions = self.actions.all()
#         events = LAMetroEvent.objects.filter(agenda__related_entities__bill=self)
# 
#         data = []
# 
#         for action in actions:
#             try:
#                 event = LAMetroEvent.objects.get(\
#                     participants__entity_type='organization',\
#                     participants__organization=action.organization,
#                     start_time__date=action.date)
#             except LAMetroEvent.DoesNotExist:
#                 logger.warning(
#                     'Could not find event corresponding to action on Board ' +
#                     'Report {0} by {1} on {2}'.format(self.identifier, action.organization, action.date)
#                 )
#                 continue
# 
#             action_dict = {
#                 'date': action.date_dt,
#                 'description': action.description,
#                 'event': event,
#                 'organization': action.organization
#             }
# 
#             data.append(action_dict)
# 
#         for event in events:
#             try:
#                 # Attempt to return Metro org object.
#                 org = LAMetroOrganization.objects.get(
#                     id=event.participants.first().organization_id
#                 )
#             except LAMetroOrganization.DoesNotExist:
#                 # If a corresponding org does not exist, e.g., in the case of
#                 # appearing on the agenda of a public hearing, return the event
#                 # participant object.
#                 org = event.participants.first()
# 
#             event_dict = {
#                 'date': event.start_time.date(),
#                 'description': 'SCHEDULED',  # Use a description of "SCHEDULED"
#                 'event': event,
#                 'organization': org
#             }
# 
#             data.append(event_dict)
# 
#         # Sort actions by date, and list SCHEDULED actions before other actions on that date
#         # SCHEDULED descriptions are kept uppercase to use ascii-betical sorting
#         sorted_data = sorted(data, key=lambda x:(x['date'],\
#             x['description'].upper() if x['description'] == 'SCHEDULED' else x['description'].lower()))
# 
#         return sorted_data


# Path: lametro/forms.py
import requests
from django import forms
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db.models import Q
from captcha.fields import ReCaptchaField
from captcha.fields import ReCaptchaV3
from haystack.backends import SQ
from haystack.inputs import Raw
from haystack.query import EmptySearchQuerySet
from councilmatic_core.views import CouncilmaticSearchForm
from lametro.models import LAMetroBill

            return EmptySearchQuerySet()

        sqs = super(LAMetroCouncilmaticSearchForm, self).search()

        has_query = hasattr(self, 'cleaned_data') and self.cleaned_data['q']

        if has_query:
            sqs = self._full_text_search(sqs)
            sqs = self._topic_search(sqs)

        return sqs


class AgendaUrlForm(forms.Form):

    agenda = forms.CharField(
        label='Agenda URL',
        max_length=500,
        error_messages={ 'required': 'Whoops! Please provide a valid URL.' },
        widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Enter URL...', 'id': 'agenda_url'}),
        )

    def clean_agenda(self):
        agenda_url = self.cleaned_data['agenda']

        try:
          r = requests.head(agenda_url)
          if r.status_code == 200:
              return agenda_url
          elif r.status_code == 404:

              raise forms.ValidationError('Broken URL! Returns a 404.')